/// <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;
        }
        public CommandResult Run(HttpRequestData request, IOptions options, HttpSessionState session)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            var urls = new OpenIDUrls(options.RPOptions, request.ApplicationUrl);

            OIDCAuthCodeResponseMessage authResponse = GetAuthResponse(request, session);
            OIDCTokenResponseMessage tokenResponse = GetToken(authResponse, options, session, urls.CodeCallbackCommand.ToString());

            OIDCUserInfoRequestMessage userInfoRequestMessage = new OIDCUserInfoRequestMessage();
            OIDCUserInfoResponseMessage userInfoResponse = GetUserInfo(authResponse, options, session, tokenResponse.AccessToken);

            var principal = GetPrincipal(userInfoResponse, options, session);
            string ReturnUrl = request.QueryString["ReturnUrl"].FirstOrDefault()?? urls.ApplicationBase.ToString();

            return new CommandResult()
            {
                HttpStatusCode = HttpStatusCode.SeeOther,
                Location = new Uri(ReturnUrl),
                Principal = principal
            };
        }
        public void Should_Authenticate_With_Claims_In_Scope_Basic()
        {
            rpid = "rp-scope-userinfo_claims";

            // given
            OIDCAuthorizationRequestMessage requestMessage = new OIDCAuthorizationRequestMessage();
            requestMessage.ClientId = clientInformation.ClientId;

            OIDClaims requestClaims = new OIDClaims();
            requestClaims.Userinfo = new Dictionary<string, OIDClaimData>();
            requestClaims.Userinfo.Add("name", new OIDClaimData());

            requestMessage.Scope = new List<MessageScope>() { MessageScope.Openid, MessageScope.Profile, MessageScope.Email, MessageScope.Address, MessageScope.Phone };
            requestMessage.ResponseType = new List<ResponseType>() { ResponseType.IdToken, ResponseType.Token };
            requestMessage.RedirectUri = clientInformation.RedirectUris[0];
            requestMessage.Nonce = WebOperations.RandomString();
            requestMessage.State = WebOperations.RandomString();
            requestMessage.Claims = requestClaims;
            requestMessage.Validate();

            OpenIdRelyingParty rp = new OpenIdRelyingParty();

            rp.Authenticate(GetBaseUrl("/authorization"), requestMessage);
            semaphore.WaitOne();
            OIDCAuthImplicitResponseMessage authResponse = rp.ParseAuthImplicitResponse(result, requestMessage.Scope, requestMessage.State);

            OIDCUserInfoRequestMessage userInfoRequestMessage = new OIDCUserInfoRequestMessage();
            userInfoRequestMessage.Scope = authResponse.Scope;
            userInfoRequestMessage.State = authResponse.State;

            // when
            OIDCUserInfoResponseMessage response = rp.GetUserInfo(GetBaseUrl("/userinfo"), userInfoRequestMessage, authResponse.AccessToken);

            // then
            response.Validate();
            Assert.IsNotNullOrEmpty(response.Name);
            Assert.IsNotNullOrEmpty(response.GivenName);
            Assert.IsNotNullOrEmpty(response.FamilyName);
            Assert.IsNotNullOrEmpty(response.Email);
            Assert.IsNotNull(response.Address);
            Assert.IsNotNullOrEmpty(response.Address.StreetAddress);
            Assert.IsNotNullOrEmpty(response.Address.PostalCode);
            Assert.IsNotNullOrEmpty(response.Address.Locality);
            Assert.IsNotNullOrEmpty(response.Address.Country);
            Assert.IsNotNullOrEmpty(response.PhoneNumber);
        }
        public void Should_Use_Distributed_Claims()
        {
            rpid = "rp-claims-distributed";
            claims = "distributed";

            // given
            OpenIdRelyingParty rp = new OpenIdRelyingParty();
            string hostname = GetBaseUrl("/");
            providerMetadata = rp.ObtainProviderInformation(hostname);

            OIDCAuthCodeResponseMessage authResponse = GetAuthResponse(ResponseType.Code, null, true) as OIDCAuthCodeResponseMessage;
            OIDCTokenResponseMessage tokenResponse = GetToken(authResponse);
            OIDCUserInfoRequestMessage userInfoRequestMessage = new OIDCUserInfoRequestMessage();

            // when
            OIDCUserInfoResponseMessage userInfoResponse = GetUserInfo(authResponse.Scope, authResponse.State, tokenResponse.AccessToken);

            // then
            Assert.NotNull(userInfoResponse);
            Assert.AreEqual(userInfoResponse.CustomClaims["age"], 30);
        }
        public OIDCUserInfoResponseMessage GetUserInfo(List<MessageScope> scope, string state, string accessToken, string idTokenSub = null, bool bearer = true, string ClientSecret = null, List<OIDCKey> RPKeys = null)
        {
            OIDCUserInfoRequestMessage userInfoRequestMessage = new OIDCUserInfoRequestMessage();
            userInfoRequestMessage.Scope = scope;
            userInfoRequestMessage.State = state;

            OpenIdRelyingParty rp = new OpenIdRelyingParty();
            var urlInfoUrl = providerMetadata.UserinfoEndpoint;
            return rp.GetUserInfo(urlInfoUrl, userInfoRequestMessage, accessToken, idTokenSub, bearer, ClientSecret, RPKeys);
        }
        private OIDCUserInfoResponseMessage GetUserInfo(OIDCAuthCodeResponseMessage authResponse, IOptions options, HttpSessionState session, string accessToken)
        {
            OpenIDProviderData providerData = options.OpenIDProviders[session["op"] as string];
            OpenIdRelyingParty rp = new OpenIdRelyingParty();

            OIDClaims requestClaims = new OIDClaims();
            requestClaims.IdToken = new Dictionary<string, OIDClaimData>();
            requestClaims.IdToken.Add("name", new OIDClaimData());
            requestClaims.IdToken.Add("family_name", new OIDClaimData());
            requestClaims.IdToken.Add("given_name", new OIDClaimData());
            requestClaims.IdToken.Add("email", new OIDClaimData());
            requestClaims.IdToken.Add("gender", new OIDClaimData());

            OIDCUserInfoRequestMessage userInfoRequestMessage = new OIDCUserInfoRequestMessage();
            userInfoRequestMessage.Scope = authResponse.Scope;
            userInfoRequestMessage.State = authResponse.State;
            userInfoRequestMessage.Claims = requestClaims;

            var urlInfoUrl = providerData.ProviderMatadata.UserinfoEndpoint;
            return rp.GetUserInfo(urlInfoUrl, userInfoRequestMessage, accessToken);
        }