/// <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");
                }
            }
        }