/// <summary> /// Get user information from the OP after user authentication /// </summary> /// <param name="url">The url to be used to retrieve user information</param> /// <param name="userInfoRequestMessage">The user info request message</param> /// <param name="accessToken">The access token obtain during authentication</param> /// <returns>The response message containing user information</returns> public OIDCUserInfoResponseMessage GetUserInfo(string url, OIDCUserInfoRequestMessage userInfoRequestMessage, string accessToken, string idTokenSub = null, bool bearer = true, string ClientSecret = null, List <OIDCKey> RPKeys = null) { WebRequest request; if (bearer) { request = WebRequest.Create(url); request.Headers.Add("Authorization", "Bearer " + accessToken); } else { request = WebRequest.Create(url + "?access_token=" + accessToken); } string returnedString = WebOperations.PostUrlContent(request, userInfoRequestMessage); string jsonToken = userInfoRequestMessage.CheckSignatureAndDecryptJWT(returnedString, null, ClientSecret, RPKeys); Dictionary <string, object> returnedJson = Deserializer.DeserializeFromJson <Dictionary <string, object> >(jsonToken); if (returnedJson.Keys.Contains("error")) { OIDCResponseError error = new OIDCResponseError(); error.DeserializeFromDictionary(returnedJson); throw new OIDCException("Error while asking for user info: " + error.Error + "\n" + error.ErrorDescription); } OIDCUserInfoResponseMessage userInfoResponse = new OIDCUserInfoResponseMessage(); userInfoResponse.DeserializeFromDictionary(returnedJson); if (idTokenSub != null && userInfoResponse.Sub != idTokenSub) { throw new OIDCException("Wrong sub in UserInfo, it does not match idToken's."); } return(userInfoResponse); }
private string ObtainIssuer(string hostname, string resource) { string query = "/.well-known/webfinger?resource=" + resource + "&rel=http://openid.net/specs/connect/1.0/issuer"; WebRequest webRequest = WebRequest.Create(hostname + query); Dictionary <string, object> o = WebOperations.GetUrlContent(webRequest); if ((DateTime)o["expires"] < DateTime.UtcNow - new TimeSpan(0, 10, 0)) { throw new OIDCException("Claims expired on " + o["expires"]); } if ((string)o["subject"] != resource) { throw new OIDCException("Claims released for a different subject."); } string issuer = null; JArray links = (JArray)o["links"]; foreach (JToken link in links) { Dictionary <string, object> dic = link.ToObject <Dictionary <string, object> >(); if (dic["rel"] as string == "http://openid.net/specs/connect/1.0/issuer") { issuer = dic["href"] as string; } } if (issuer == null) { throw new OIDCException("No issuer found in claims returned."); } return(issuer); }
public static void ParseAggregatedClaims(OIDCUserInfoResponseMessage obj, Dictionary <string, object> data) { if (data.ContainsKey("_claim_names") && data["_claim_names"] != null) { Dictionary <string, object> claims = (data["_claim_names"] as JObject).ToObject <Dictionary <string, object> >(); foreach (KeyValuePair <string, object> kvp in claims) { string name = kvp.Key; string path = kvp.Value.ToString(); if (!data.ContainsKey("_claim_sources") || data["_claim_sources"] == null) { continue; } dynamic sources = data["_claim_sources"]; foreach (JProperty s in sources) { if (s.Name != path) { continue; } dynamic vals = s.Value; foreach (JProperty v in sources) { Dictionary <string, object> values = null; Dictionary <string, object> val = (v.Value as JObject).ToObject <Dictionary <string, object> >(); if (val.ContainsKey("JWT")) { string json = JWT.Decode(val["JWT"].ToString()); values = DeserializeFromJson <Dictionary <string, object> >(json); } else if (val.ContainsKey("endpoint")) { WebRequest req = WebRequest.Create(val["endpoint"].ToString()); if (val.ContainsKey("access_token")) { req.Headers.Add("Authorization", "Bearer " + val["access_token"].ToString()); } values = WebOperations.GetUrlContent(req); } if (!values.ContainsKey(name)) { continue; } if (obj.CustomClaims == null) { obj.CustomClaims = new Dictionary <string, object>(); } obj.CustomClaims[name] = values[name]; } } } } }
private OIDCClientSecretJWT AddClientAuthenticatedToRequest(ref WebRequest request, ref OIDCAuthenticatedMessage requestMessage, string grantType, OIDCClientInformation clientInformation, byte[] privateKey) { OIDCClientSecretJWT tokenData = null; byte[] encKey = null; switch (grantType) { case "client_secret_basic": string basic = clientInformation.ClientId + ":" + clientInformation.ClientSecret; basic = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes(basic)); request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(basic))); break; case "client_secret_post": requestMessage.ClientId = clientInformation.ClientId; requestMessage.ClientSecret = clientInformation.ClientSecret; break; case "client_secret_jwt": encKey = Encoding.UTF8.GetBytes(clientInformation.ClientSecret); break; case "private_key_jwt": encKey = privateKey; break; default: // case "none" break; } // If client_secret_jwt or private_key_jwt pass a JWT bearer token with the // specified key for encryption. if (encKey != null) { tokenData = new OIDCClientSecretJWT(); tokenData.Iss = clientInformation.ClientId; tokenData.Sub = clientInformation.ClientId; tokenData.Aud = request.RequestUri.ToString(); if (tokenData.Aud.Contains("?")) { tokenData.Aud = tokenData.Aud.Substring(0, tokenData.Aud.IndexOf("?")); } tokenData.Jti = WebOperations.RandomString(); tokenData.Exp = DateTime.Now; tokenData.Iat = DateTime.Now - new TimeSpan(0, 10, 0); requestMessage.ClientAssertionType = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"; requestMessage.ClientAssertion = JWT.Encode(tokenData, encKey, Jose.JwsAlgorithm.HS256); } return(tokenData); }
/// <summary> /// Method that queries the OP server to obtain the OpenID configuration. /// </summary> /// <param name="hostname">The hostname of the OP to be queried.</param> /// <param name="expectedIssuer">(optional) the issuer expected from the OP configuration. /// This information can come, for instance, from a previous issuer discovery process /// via webfinger.</param> /// <returns>An oject describing all relevant properties of the OP.</returns> /// <exception cref="OpenIDClient.OIDCException">Thrown when the returned message from server /// is not valid or if wrong issuer is found in the answer.</exception> public OIDCProviderMetadata ObtainProviderInformation(string hostname, string expectedIssuer = null) { string query = "/.well-known/openid-configuration"; WebRequest webRequest = WebRequest.Create(hostname + query); Dictionary <string, object> o = WebOperations.GetUrlContent(webRequest); OIDCProviderMetadata providerMetadata = new OIDCProviderMetadata(o); if (expectedIssuer != null && !expectedIssuer.Equals(providerMetadata.Issuer)) { throw new OIDCException("Wrong issuer, discarding configuration"); } return(providerMetadata); }
/// <summary> /// Constructor deserializing message properties from dictionary. /// </summary> /// <param name="o">The dictionary object containing message properties.</param> public OIDCProviderMetadata(Dictionary <string, object> o) { DeserializeFromDictionary(o); if (JwksUri != null) { Keys = new List <OIDCKey>(); Dictionary <string, object> jwks = WebOperations.GetUrlContent(WebRequest.Create(JwksUri)); JArray keys = (JArray)jwks["keys"]; foreach (JToken key in keys) { OIDCKey newKey = new OIDCKey(key.ToObject <Dictionary <string, object> >()); Keys.Add(newKey); } } }
/// <summary> /// Method that sends authentication request to the OP. /// </summary> /// <param name="AuthenticateUrl">The URL to be used for the authentication request.</param> /// <param name="RequestMessage">The reuqest message to be sent to the OP.</param> /// <param name="Certificate">The certificate to be used, in case of a self-issued authentication.</param> /// <returns>The authentication response from the OP.</returns> public OIDCAuthImplicitResponseMessage Authenticate(string AuthenticateUrl, OIDCAuthorizationRequestMessage RequestMessage, X509Certificate2 Certificate = null) { if (new Uri(AuthenticateUrl).Scheme == "openid") { // we are dealing with a Self-Issued OpenID provider Dictionary <string, object> response = PerformSelfIssuedAuthentication(RequestMessage, Certificate); OIDCAuthImplicitResponseMessage responseMessage = new OIDCAuthImplicitResponseMessage(); responseMessage.DeserializeFromDictionary(response); return(responseMessage); } else { string login_url = AuthenticateUrl + "?" + RequestMessage.SerializeToQueryString(); WebOperations.GetUrlContent(WebRequest.Create(login_url)); return(null); } }
/// <summary> /// Method that submits a tokn request to the OP. /// </summary> /// <param name="url">The URL to be used where to send the request</param> /// <param name="tokenRequestMessage">The token request message</param> /// <param name="clientInformation">The client information obtained from the OP</param> /// <returns>Returns the token response obtained from the OP</returns> public OIDCTokenResponseMessage SubmitTokenRequest(string url, OIDCTokenRequestMessage tokenRequestMessage, OIDCClientInformation clientInformation, byte[] privateKey = null) { WebRequest request = WebRequest.Create(url); OIDCAuthenticatedMessage message = tokenRequestMessage as OIDCAuthenticatedMessage; string grantType = clientInformation.TokenEndpointAuthMethod; AddClientAuthenticatedToRequest(ref request, ref message, grantType, clientInformation, privateKey); string returnedString = WebOperations.PostUrlContent(request, message); Dictionary <string, object> returnedJson = Deserializer.DeserializeFromJson <Dictionary <string, object> >(returnedString); if (returnedJson.Keys.Contains("error")) { OIDCResponseError error = new OIDCResponseError(); error.DeserializeFromDictionary(returnedJson); throw new OIDCException("Error while registering client: " + error.Error + "\n" + error.ErrorDescription); } OIDCTokenResponseMessage tokenResponse = new OIDCTokenResponseMessage(); tokenResponse.DeserializeFromDictionary(returnedJson); return(tokenResponse); }
/// <summary> /// Method that performs a dynamic client registration with the OP server. /// </summary> /// <param name="RegistrationEndpoint">The URL of the OP describing the registration endpoint.</param> /// <param name="clientMetadata">The OIDCClientInformation object describing the client information to /// be submitted to the OP for registration.</param> /// <param name="TokenEndpointAuthMethod">(optional) the endpoint authentication method used to /// authenticate the client with the OP sever (if not specified using "client_secret_basic".</param> /// <returns>An oject describing all client information as returned by the OP server after /// registration.</returns> /// <exception cref="OpenIDClient.OIDCException">Thrown when an error occurs while registering /// the client with the OP.</exception> public OIDCClientInformation RegisterClient(string RegistrationEndpoint, OIDCClientInformation clientMetadata, string TokenEndpointAuthMethod = "client_secret_basic") { // Make registration request Dictionary <string, object> data = clientMetadata.SerializeToDictionary(); OIDCClientRegistrationRequest registrationRequest = new OIDCClientRegistrationRequest(); registrationRequest.DeserializeFromDictionary(data); // Check error and store client information from OP WebRequest request = WebRequest.Create(RegistrationEndpoint); string returnedString = WebOperations.PostUrlContent(request, registrationRequest, true); Dictionary <string, object> returnedJson = Deserializer.DeserializeFromJson <Dictionary <string, object> >(returnedString); if (returnedJson.Keys.Contains("error")) { OIDCResponseError error = new OIDCResponseError(); throw new OIDCException("Error while registering client: " + error.Error + "\n" + error.ErrorDescription); } OIDCClientInformation clientInformation = new OIDCClientInformation(); clientInformation.DeserializeFromDictionary(returnedJson); return(clientInformation); }
/// <summary> /// Method to perform third party initiated login. /// </summary> /// <param name="queryString">The query string representation of the authentication request</param> /// <param name="authEndpoint">The OP authorization endpoint</param> public void ThirdPartyInitiatedLogin(OIDCAuthorizationRequestMessage requestMessage, string authEndpoint) { string login_url = authEndpoint + "?" + requestMessage.SerializeToQueryString(); WebOperations.GetUrlContent(WebRequest.Create(login_url)); }
/// <summary> /// <see cref="OIDClientSerializableMessage.Validate()"/> /// </summary> public override void Validate() { if (RedirectUris != null && ResponseTypes != null && RedirectUris.Count != ResponseTypes.Count) { throw new OIDCException("The redirect_uris do not match response_types."); } if (RedirectUris != null && SectorIdentifierUri != null) { List <string> siUris = new List <string>(); dynamic uris = WebOperations.GetUrlContent(WebRequest.Create(SectorIdentifierUri)); foreach (string uri in uris) { siUris.Add(uri); } foreach (string uri in RedirectUris) { if (!siUris.Contains(uri)) { throw new OIDCException("The sector_identifier_uri json must include URIs from the redirect_uri array."); } } } if (ResponseTypes != null && GrantTypes != null) { foreach (ResponseType responseType in ResponseTypes) { if ((responseType == ResponseType.Code && !GrantTypes.Contains("authorization_code")) || (responseType == ResponseType.IdToken && !GrantTypes.Contains("implicit")) || (responseType == ResponseType.Token && !GrantTypes.Contains("implicit"))) { throw new OIDCException("The response_types do not match grant_types."); } } } List <string> listUri = new List <string>() { LogoUri, ClientUri, PolicyUri, TosUri, JwksUri, SectorIdentifierUri, InitiateLoginUri, RegistrationClientUri }; if (RedirectUris != null) { listUri.AddRange(RedirectUris); } if (RequestUris != null) { listUri.AddRange(RequestUris); } foreach (string uri in listUri) { if (uri == null) { continue; } if (new Uri(uri).Scheme != "https") { throw new OIDCException("Some of the URIs for the client is not on https"); } } }