Exemple #1
0
        /// <summary>
        /// Custom validation logic for identity tokens.
        /// </summary>
        /// <param name="result">The validation result so far.</param>
        /// <returns>
        /// The validation result
        /// </returns>
        public virtual async Task <TokenValidationResult> ValidateIdentityTokenAsync(TokenValidationResult result)
        {
            // make sure user is still active (if sub claim is present)
            var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject);

            if (subClaim != null)
            {
                var principal = Principal.Create("tokenvalidator", result.Claims.ToArray());

                var isActiveCtx = new IsActiveContext(principal, result.Client, IdentityServerConstants.ProfileIsActiveCallers.IdentityTokenValidation);
                await Profile.IsActiveAsync(isActiveCtx);

                if (isActiveCtx.IsActive == false)
                {
                    Logger.LogError("User marked as not active: {subject}", subClaim.Value);

                    result.IsError = true;
                    result.Error   = OidcConstants.ProtectedResourceErrors.InvalidToken;
                    result.Claims  = null;

                    return(result);
                }
            }

            return(result);
        }
Exemple #2
0
        public virtual TokenResponse CreateTokenResponseFromAuthorizationCode(StoredGrant handle, IStoredGrantManager handleManager)
        {
            var resourceOwner = Principal.Create(
                "OAuth2",
                handle.ResourceOwner.ToClaims().ToArray());

            var validatedRequest = new ValidatedRequest
            {
                Client      = handle.Client,
                Application = handle.Application,
                Scopes      = handle.Scopes
            };

            var response = CreateTokenResponse(validatedRequest, resourceOwner);

            if (handle.CreateRefreshToken)
            {
                var refreshTokenHandle = StoredGrant.CreateRefreshTokenHandle(
                    resourceOwner.GetSubject(),
                    handle.Client,
                    handle.Application,
                    resourceOwner.Claims,
                    handle.Scopes,
                    handle.RefreshTokenExpiration.Value);

                handleManager.Add(refreshTokenHandle);
                response.RefreshToken = refreshTokenHandle.GrantId;
            }

            handleManager.Delete(handle.GrantId);

            return(response);
        }
Exemple #3
0
        public async Task <Dictionary <string, object> > ProcessAsync(string subject, IEnumerable <string> scopes)
        {
            Logger.Info("Creating userinfo response");
            var profileData = new Dictionary <string, object>();

            var requestedClaimTypes = await GetRequestedClaimTypesAsync(scopes);

            var principal = Principal.Create("UserInfo", new Claim("sub", subject));

            IEnumerable <Claim> profileClaims;

            if (requestedClaimTypes.IncludeAllClaims)
            {
                Logger.InfoFormat("Requested claim types: all");
                profileClaims = await _users.GetProfileDataAsync(principal);
            }
            else
            {
                Logger.InfoFormat("Requested claim types: {0}", requestedClaimTypes.ClaimTypes.ToSpaceSeparatedString());
                profileClaims = await _users.GetProfileDataAsync(principal, requestedClaimTypes.ClaimTypes);
            }

            if (profileClaims != null)
            {
                profileData = profileClaims.ToClaimsDictionary();
                Logger.InfoFormat("Profile service returned to the following claim types: {0}", profileClaims.Select(c => c.Type).ToSpaceSeparatedString());
            }
            else
            {
                Logger.InfoFormat("Profile service returned no claims (null)");
            }

            return(profileData);
        }
    /// <summary>
    /// Validates a userinfo request.
    /// </summary>
    /// <param name="accessToken">The access token.</param>
    /// <returns></returns>
    /// <exception cref="System.NotImplementedException"></exception>
    public async Task <UserInfoRequestValidationResult> ValidateRequestAsync(string accessToken)
    {
        using var activity = Tracing.BasicActivitySource.StartActivity("UserInfoRequestValidator.ValidateRequest");

        // the access token needs to be valid and have at least the openid scope
        var tokenResult = await _tokenValidator.ValidateAccessTokenAsync(
            accessToken,
            IdentityServerConstants.StandardScopes.OpenId);

        if (tokenResult.IsError)
        {
            return(new UserInfoRequestValidationResult
            {
                IsError = true,
                Error = tokenResult.Error
            });
        }

        // the token must have a one sub claim
        var subClaim = tokenResult.Claims.SingleOrDefault(c => c.Type == JwtClaimTypes.Subject);

        if (subClaim == null)
        {
            _logger.LogError("Token contains no sub claim");

            return(new UserInfoRequestValidationResult
            {
                IsError = true,
                Error = OidcConstants.ProtectedResourceErrors.InvalidToken
            });
        }

        // create subject from incoming access token
        var claims  = tokenResult.Claims.Where(x => !Constants.Filters.ProtocolClaimsFilter.Contains(x.Type));
        var subject = Principal.Create("UserInfo", claims.ToArray());

        // make sure user is still active
        var isActiveContext = new IsActiveContext(subject, tokenResult.Client, IdentityServerConstants.ProfileIsActiveCallers.UserInfoRequestValidation);
        await _profile.IsActiveAsync(isActiveContext);

        if (isActiveContext.IsActive == false)
        {
            _logger.LogError("User is not active: {sub}", subject.GetSubjectId());

            return(new UserInfoRequestValidationResult
            {
                IsError = true,
                Error = OidcConstants.ProtectedResourceErrors.InvalidToken
            });
        }

        return(new UserInfoRequestValidationResult
        {
            IsError = false,
            TokenValidationResult = tokenResult,
            Subject = subject
        });
    }
        public void Init()
        {
            DataProtectection.Instance = new NoProtection();

            _testConfig = new TestAuthorizationServerConfiguration();
            _client     = Principal.Create("Test",
                                           new Claim("client_id", "client"),
                                           new Claim("secret", "secret"));
        }
Exemple #6
0
        public Task <ClaimsPrincipal> ValidateAsync(ValidatedTokenRequest request, IUserService users)
        {
            if (request.GrantType == "assertionType" && request.Assertion == "assertion")
            {
                return(Task.FromResult(Principal.Create("Assertion", new Claim("sub", "bob"))));
            }
            ;

            return(Task.FromResult <ClaimsPrincipal>(null));
        }
        public void CreateAuthenticatedPrincipal()
        {
            var p = Principal.Create("Test",
                                     new Claim(ClaimTypes.Name, "test"));

            Assert.IsTrue(p.Identity.IsAuthenticated);
            Assert.AreEqual <string>(p.Identities.First().AuthenticationType, "Test");
            Assert.AreEqual <int>(p.Identities.Count(), 1);
            Assert.AreEqual <int>(p.Identities.First().Claims.Count(), 1);
        }
        public Task <ClaimsPrincipal> ValidateAsync(ValidatedTokenRequest request)
        {
            if (request.GrantType == "customGrant")
            {
                return(Task.FromResult(Principal.Create("CustomGrant", new Claim("sub", "bob"))));
            }
            ;

            return(Task.FromResult <ClaimsPrincipal>(null));
        }
Exemple #9
0
        /// <summary>
        /// Custom validation logic for access tokens.
        /// </summary>
        /// <param name="result">The validation result so far.</param>
        /// <returns>
        /// The validation result
        /// </returns>
        public virtual async Task <TokenValidationResult> ValidateAccessTokenAsync(TokenValidationResult result)
        {
            if (result.IsError)
            {
                return(result);
            }

            // make sure user is still active (if sub claim is present)
            var subClaim = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject);

            if (subClaim != null)
            {
                var principal = Principal.Create("tokenvalidator", result.Claims.ToArray());

                if (result.ReferenceTokenId.IsPresent())
                {
                    principal.Identities.First().AddClaim(new Claim(Constants.ClaimTypes.ReferenceTokenId, result.ReferenceTokenId));
                }

                var isActiveCtx = new IsActiveContext(principal, result.Client);
                await _users.IsActiveAsync(isActiveCtx);

                if (isActiveCtx.IsActive == false)
                {
                    Logger.Warn("User marked as not active: " + subClaim.Value);

                    result.IsError = true;
                    result.Error   = Constants.ProtectedResourceErrors.InvalidToken;
                    result.Claims  = null;

                    return(result);
                }
            }

            // make sure client is still active (if client_id claim is present)
            var clientClaim = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.ClientId);

            if (clientClaim != null)
            {
                var client = await _clients.FindClientByIdAsync(clientClaim.Value);

                if (client == null || client.Enabled == false)
                {
                    Logger.Warn("Client deleted or disabled: " + clientClaim.Value);

                    result.IsError = true;
                    result.Error   = Constants.ProtectedResourceErrors.InvalidToken;
                    result.Claims  = null;

                    return(result);
                }
            }

            return(result);
        }
        public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
        {
            var subject = GetSubject(incomingPrincipal);
            var claims  = new List <Claim> {
                new Claim(Constants.ClaimTypes.Subject, subject)
            };

            claims.AddRange(AddInternalClaims(subject));

            return(Principal.Create("AuthorizationServer", claims.ToArray()));
        }
        private async Task <IEndpointResult> ProcessUserInfoRequestAsync(HttpContext context)
        {
            _logger.LogDebug("Start userinfo request");

            var tokenUsageResult = await _tokenUsageValidator.ValidateAsync(context);

            if (tokenUsageResult.TokenFound == false)
            {
                var error = "No access token found.";

                _logger.LogError(error);
                await RaiseFailureEventAsync(error);

                return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken));
            }

            _logger.LogDebug("Token found: {bearerTokenUsageType}", tokenUsageResult.UsageType.ToString());

            var tokenResult = await _tokenValidator.ValidateAccessTokenAsync(
                tokenUsageResult.Token,
                Constants.StandardScopes.OpenId);

            if (tokenResult.IsError)
            {
                _logger.LogError(tokenResult.Error);
                await RaiseFailureEventAsync(tokenResult.Error);

                return(Error(tokenResult.Error));
            }

            // pass scopes/claims to profile service
            var claims  = tokenResult.Claims.Where(x => !Constants.Filters.ProtocolClaimsFilter.Contains(x.Type));
            var subject = Principal.Create("UserInfo", claims.ToArray());

            if (subject.FindFirst(JwtClaimTypes.Subject) == null)
            {
                var error = "Token contains no sub claim";
                _logger.LogError(error);
                await RaiseFailureEventAsync(error);

                return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken));
            }

            var scopes = tokenResult.Claims.Where(c => c.Type == JwtClaimTypes.Scope).Select(c => c.Value);

            var payload = await _generator.ProcessAsync(subject, scopes, tokenResult.Client);

            _logger.LogDebug("End userinfo request");
            await RaiseSuccessEventAsync();

            return(new UserInfoResult(payload));
        }
        public async Task <Dictionary <string, object> > ProcessAsync(string subject, IEnumerable <string> scopes, Client client)
        {
            _logger.LogTrace("Creating userinfo response");

            var profileData = new Dictionary <string, object>();

            var requestedClaimTypes = await GetRequestedClaimTypesAsync(scopes);

            var principal = Principal.Create("UserInfo", new Claim("sub", subject));

            IEnumerable <Claim> profileClaims;

            if (requestedClaimTypes.IncludeAllClaims)
            {
                _logger.LogInformation("Requested claim types: all");

                var context = new ProfileDataRequestContext(
                    principal,
                    client,
                    Constants.ProfileDataCallers.UserInfoEndpoint);

                await _profile.GetProfileDataAsync(context);

                profileClaims = context.IssuedClaims;
            }
            else
            {
                _logger.LogInformation("Requested claim types: {types}", requestedClaimTypes.ClaimTypes.ToSpaceSeparatedString());

                var context = new ProfileDataRequestContext(
                    principal,
                    client,
                    Constants.ProfileDataCallers.UserInfoEndpoint,
                    requestedClaimTypes.ClaimTypes);

                await _profile.GetProfileDataAsync(context);

                profileClaims = context.IssuedClaims;
            }

            if (profileClaims != null)
            {
                profileData = profileClaims.ToClaimsDictionary();
                _logger.LogInformation("Profile service returned to the following claim types: {types}", profileClaims.Select(c => c.Type).ToSpaceSeparatedString());
            }
            else
            {
                _logger.LogInformation("Profile service returned no claims (null)");
            }

            return(profileData);
        }
        public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
        {
            if (!incomingPrincipal.Identity.IsAuthenticated)
            {
                return(base.Authenticate(resourceName, incomingPrincipal));
            }

            var name = incomingPrincipal.Identity.Name;

            return(Principal.Create(
                       "Custom",
                       new Claim(ClaimTypes.Name, name + " (transformed)")));
        }
        public void Init()
        {
            DataProtectection.Instance = new NoProtection();

            _testConfig         = new TestAuthorizationServerConfiguration();
            _storedGrantManager = new TestTokenHandleManager("abc", "client", "https://validredirect");

            _clientManager = new TestClientManager()
            {
                Id = "client", Secret = "secret", OAuthFlow = OAuthFlow.Client, AllowRefreshTokens = false
            };
            _client = Principal.Create("Test", new Claim("client_id", "client"), new Claim("secret", "secret"));
        }
        public void CreateAuthenticatedPrincipalWithEmptyRoles()
        {
            var p = Principal.Create("Test",
                                     new Claim(ClaimTypes.Name, "test"));

            var roles = Principal.CreateRoles(new string[] { });

            p.Identities.First().AddClaims(roles);

            Assert.IsTrue(p.Identity.IsAuthenticated);
            Assert.AreEqual <string>(p.Identities.First().AuthenticationType, "Test");
            Assert.AreEqual <int>(p.Identities.Count(), 1);
            Assert.AreEqual <int>(p.Identities.First().Claims.Count(), 1);
        }
        public void Init()
        {
            DataProtectection.Instance = new NoProtection();

            _testConfig = new TestAuthorizationServerConfiguration();
            _client     = Principal.Create(
                "Test",
                new Claim("client_id", "codeclient"),
                new Claim("secret", "secret"));
            _handleManager = new TestTokenHandleManager(
                "abc",
                "codeclient",
                "https://validredirect");
        }
        /// <summary>
        /// Creates a principal from the subject id and additional claims
        /// </summary>
        /// <param name="subjectId">Subject ID</param>
        /// <param name="additionalClaims">Additional claims</param>
        /// <returns>ClaimsPrincipal</returns>
        public static ClaimsPrincipal FromSubjectId(string subjectId, IEnumerable <Claim> additionalClaims = null)
        {
            var claims = new List <Claim>
            {
                new Claim(Constants.ClaimTypes.Subject, subjectId)
            };

            if (additionalClaims != null)
            {
                claims.AddRange(additionalClaims);
            }

            return(Principal.Create(Constants.PrimaryAuthenticationType,
                                    claims.Distinct(new ClaimComparer()).ToArray()));
        }
        /// <summary>
        /// Custom validation logic for access tokens.
        /// </summary>
        /// <param name="result">The validation result so far.</param>
        /// <returns>
        /// The validation result
        /// </returns>
        public async Task <TokenValidationResult> ValidateAccessTokenAsync(TokenValidationResult result)
        {
            if (result.IsError)
            {
                return(result);
            }

            // make sure user is still active (if sub claim is present)
            var subClaim = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject);

            if (subClaim != null)
            {
                var principal = Principal.Create("tokenvalidator", result.Claims.ToArray());

                if (result.ReferenceTokenId.IsPresent())
                {
                    principal.Identities.First().AddClaim(new Claim(Constants.ClaimTypes.ReferenceTokenId, result.ReferenceTokenId));
                }

                if (await _users.IsActiveAsync(principal) == false)
                {
                    result.IsError = true;
                    result.Error   = Constants.ProtectedResourceErrors.ExpiredToken;
                    result.Claims  = null;

                    return(result);
                }
            }

            // make sure client is still active (if client_id claim is present)
            var clientClaim = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.ClientId);

            if (clientClaim != null)
            {
                var client = await _clients.FindClientByIdAsync(clientClaim.Value);

                if (client == null || client.Enabled == false)
                {
                    result.IsError = true;
                    result.Error   = Constants.ProtectedResourceErrors.ExpiredToken;
                    result.Claims  = null;

                    return(result);
                }
            }

            return(result);
        }
Exemple #19
0
        public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
        {
            if (!incomingPrincipal.Identity.IsAuthenticated)
            {
                return(base.Authenticate(resourceName, incomingPrincipal));
            }

            var name = GetName(incomingPrincipal);
            var role = GetRole(incomingPrincipal);

            var principal = Principal.Create("Windows", name, role);

            EstablishSession(principal);

            return(principal);
        }
        public HttpResponseMessage Get()
        {
            Tracing.Start("OIDC UserInfo endpoint");

            var details = new RequestDetails {
                IsOpenIdRequest = true
            };
            var scopeClaims     = ClaimsPrincipal.Current.FindAll(OAuth2Constants.Scope).ToList();
            var requestedClaims = ClaimsPrincipal.Current.FindAll("requestclaim").ToList();

            if (scopeClaims.Count > 0)
            {
                var scopes = new List <string>(scopeClaims.Select(sc => sc.Value));
                details.OpenIdScopes = scopes;
            }

            if (requestedClaims.Count > 0)
            {
                var requestClaims = new RequestClaimCollection();
                requestedClaims.ForEach(rc => requestClaims.Add(new RequestClaim(rc.Value)));

                details.ClaimsRequested = true;
                details.RequestClaims   = requestClaims;
            }

            var principal = Principal.Create("OpenIdConnect",
                                             new Claim(ClaimTypes.Name, ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value));

            var claims = ClaimsRepository.GetClaims(principal, details);

            var dictionary = new Dictionary <string, string>();

            foreach (var claim in claims)
            {
                if (!dictionary.ContainsKey(claim.Type))
                {
                    dictionary.Add(claim.Type, claim.Value);
                }
                else
                {
                    var currentValue = dictionary[claim.Type];
                    dictionary[claim.Type] = currentValue += ("," + claim.Value);
                }
            }

            return(Request.CreateResponse <Dictionary <string, string> >(HttpStatusCode.OK, dictionary, "application/json"));
        }
Exemple #21
0
        public async Task <DeviceAuthorizationResponse> Generate(DeviceAuthorizationRequestValidationResult validationResult)
        {
            var authorizationCode = new TrustedDeviceAuthorizationCode {
                ClientId        = validationResult.Client.ClientId,
                CodeChallenge   = validationResult.CodeChallenge.Sha256(),
                CreationTime    = SystemClock.UtcNow.UtcDateTime,
                DeviceId        = validationResult.Device.DeviceId,
                InteractionMode = validationResult.InteractionMode,
                Lifetime        = validationResult.Client.AuthorizationCodeLifetime,
                RequestedScopes = validationResult.RequestedScopes,
                Subject         = Principal.Create("TrustedDevice", new Claim(JwtClaimTypes.Subject, validationResult.UserId))
            };
            var challenge = await CodeChallengeStore.GenerateChallenge(authorizationCode);

            return(new DeviceAuthorizationResponse {
                Challenge = challenge
            });
        }
        public IActionResult LogIn()
        {
            ResponseModel Result = new ResponseModel();

            LogInModel account = new LogInModel()
            {
                Account_Account  = Request.Form["Account_Account"],
                Account_Password = Request.Form["Account_Password"]
            };

            AccountModel user;

            try{
                if (ModelState.IsValid)
                {
                    user = Principal.Create(account.Account_Account, account.Account_Password, ConfigHelper.ConnectionString);

                    SetUserSession(user);
                    Result.HttpStatus = "1";
                    Result.Message    = "ok";
                }
            }
            catch (LogInException ex) {
                Result.HttpStatus = ex.Key;
                Result.Message    = ex.Message;
            }
            catch (Exception ex) {
                switch (ex.Source)
                {
                case "MySql.Data":
                    Result.HttpStatus = "510";
                    Result.Message    = "伺服器發生錯誤。";
                    break;

                default:
                    Result.HttpStatus = "0";
                    Result.Message    = ex.Message;
                    break;
                }
            }
            return(Json(Result));
        }
        /// <summary>
        /// Validates a userinfo request.
        /// </summary>
        /// <param name="accessToken">The access token.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public async Task <UserInfoRequestValidationResult> ValidateRequestAsync(string accessToken)
        {
            // the access token needs to be valid and have at least the openid scope
            var tokenResult = await _tokenValidator.ValidateAccessTokenAsync(
                accessToken,
                IdentityServerConstants.StandardScopes.OpenId);

            if (tokenResult.IsError)
            {
                return(new UserInfoRequestValidationResult
                {
                    IsError = true,
                    Error = tokenResult.Error
                });
            }

            // the token must have a one sub claim
            var subClaim = tokenResult.Claims.SingleOrDefault(c => c.Type == JwtClaimTypes.Subject);

            if (subClaim == null)
            {
                _logger.LogError("Token contains no sub claim");

                return(new UserInfoRequestValidationResult
                {
                    IsError = true,
                    Error = OidcConstants.ProtectedResourceErrors.InvalidToken
                });
            }

            // create subject from incoming access token
            var claims  = tokenResult.Claims.Where(x => !Constants.Filters.ProtocolClaimsFilter.Contains(x.Type));
            var subject = Principal.Create("UserInfo", claims.ToArray());

            return(new UserInfoRequestValidationResult
            {
                IsError = false,
                TokenValidationResult = tokenResult,
                Subject = subject
            });
        }
        public void Refresh_Token_Create_New()
        {
            Claim[]         claims          = { new Claim("client_id", "MobileAppShop"), new Claim("secret", "12345678") };
            ClaimsPrincipal claimsPrinciple = Principal.Create("Test", claims);

            Thread.CurrentPrincipal = claimsPrinciple;

            TokenRequest tokenRequest = new TokenRequest()
            {
                Grant_Type    = "refresh_token",
                Refresh_Token = "MyFavouriteRefrehToken1234"
            };

            var           response = _TokenController.Post("Test Application 1", tokenRequest);
            TokenResponse tokenResponse;

            response.TryGetContentValue <TokenResponse>(out tokenResponse);

            Assert.IsTrue(response.IsSuccessStatusCode == true);
            Assert.IsFalse(string.IsNullOrEmpty(tokenResponse.AccessToken));
        }
        /// <summary>
        /// Custom validation logic for identity tokens.
        /// </summary>
        /// <param name="result">The validation result so far.</param>
        /// <returns>
        /// The validation result
        /// </returns>
        public async Task <TokenValidationResult> ValidateIdentityTokenAsync(TokenValidationResult result)
        {
            // make sure user is still active (if sub claim is present)
            var subClaim = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject);

            if (subClaim != null)
            {
                var principal = Principal.Create("tokenvalidator", result.Claims.ToArray());

                if (await _users.IsActiveAsync(principal) == false)
                {
                    result.IsError = true;
                    result.Error   = Constants.ProtectedResourceErrors.ExpiredToken;
                    result.Claims  = null;

                    return(result);
                }
            }

            return(result);
        }
        public void Create_Token()
        {
            Claim[]         claims          = { new Claim("client_id", "MobileAppShop"), new Claim("secret", "12345678") };
            ClaimsPrincipal claimsPrinciple = Principal.Create("Test", claims);

            Thread.CurrentPrincipal = claimsPrinciple;

            TokenRequest tokenRequest = new TokenRequest()
            {
                Grant_Type = "password",
                UserName   = "******",
                Password   = "******",
                Scope      = "read",
            };

            var           response = _TokenController.Post("Test Application 1", tokenRequest);
            TokenResponse tokenResponse;

            response.TryGetContentValue <TokenResponse>(out tokenResponse);

            Assert.IsTrue(response.IsSuccessStatusCode == true);
            Assert.IsFalse(string.IsNullOrEmpty(tokenResponse.AccessToken));
        }
        public virtual TokenResponse CreateTokenResponseFromRefreshToken(StoredGrant handle, IStoredGrantManager handleManager)
        {
            var resourceOwner = Principal.Create(
                "OAuth2",
                handle.ResourceOwner.ToClaims().ToArray());

            if (DateTime.UtcNow > handle.Expiration)
            {
                throw new InvalidOperationException("Refresh token has expired.");
            }

            var validatedRequest = new ValidatedRequest
            {
                Client      = handle.Client,
                Application = handle.Application,
                Scopes      = handle.Scopes,
            };

            var response = CreateTokenResponse(validatedRequest, resourceOwner);

            response.RefreshToken = handle.GrantId;

            return(response);
        }
Exemple #28
0
        public async Task <TokenValidationResult> ValidateIdentityTokenAsync(string token, string clientId = null, bool validateLifetime = true)
        {
            _logger.LogDebug("Start identity token validation");

            if (token.Length > _options.InputLengthRestrictions.Jwt)
            {
                _logger.LogError("JWT too long");
                return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken));
            }

            if (clientId.IsMissing())
            {
                clientId = GetClientIdFromJwt(token);

                if (clientId.IsMissing())
                {
                    _logger.LogError("No clientId supplied, can't find id in identity token.");
                    return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken));
                }
            }

            _log.ClientId         = clientId;
            _log.ValidateLifetime = validateLifetime;

            var client = await _clients.FindEnabledClientByIdAsync(clientId);

            if (client == null)
            {
                _logger.LogError("Unknown or disabled client: {clientId}.", clientId);
                return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken));
            }

            _log.ClientName = client.ClientName;
            _logger.LogDebug("Client found: {clientId} / {clientName}", client.ClientId, client.ClientName);

            var keys = await _keys.GetValidationKeysAsync();

            var result = await ValidateJwtAsync(token, clientId, keys, validateLifetime);

            result.Client = client;

            if (result.IsError)
            {
                LogError("Error validating JWT");
                return(result);
            }

            _log.Claims = result.Claims.ToClaimsDictionary();

            // make sure user is still active (if sub claim is present)
            var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject);

            if (subClaim != null)
            {
                var principal = Principal.Create("tokenvalidator", result.Claims.ToArray());

                var isActiveCtx = new IsActiveContext(principal, result.Client, IdentityServerConstants.ProfileIsActiveCallers.IdentityTokenValidation);
                await _profile.IsActiveAsync(isActiveCtx);

                if (isActiveCtx.IsActive == false)
                {
                    _logger.LogError("User marked as not active: {subject}", subClaim.Value);

                    result.IsError = true;
                    result.Error   = OidcConstants.ProtectedResourceErrors.InvalidToken;
                    result.Claims  = null;

                    return(result);
                }
            }

            _logger.LogDebug("Calling into custom token validator: {type}", _customValidator.GetType().FullName);
            var customResult = await _customValidator.ValidateIdentityTokenAsync(result);

            if (customResult.IsError)
            {
                LogError("Custom validator failed: " + (customResult.Error ?? "unknown"));
                return(customResult);
            }

            _log.Claims = customResult.Claims.ToClaimsDictionary();

            LogSuccess();
            return(customResult);
        }
Exemple #29
0
        public override async Task <CompleteRegistrationRequestValidationResult> Validate(NameValueCollection parameters, string accessToken = null)
        {
            Logger.LogDebug($"[{nameof(CompleteRegistrationRequestValidator)}] Started trusted device registration request validation.");
            // The access token needs to be valid and have at least the openid scope.
            var tokenValidationResult = await TokenValidator.ValidateAccessTokenAsync(accessToken, IdentityServerConstants.StandardScopes.OpenId);

            if (tokenValidationResult.IsError)
            {
                return(Error(tokenValidationResult.Error, "Provided access token is not valid."));
            }
            // The access token must have at lease a 'sub' and 'client_id' claim.
            var claimsToValidate = new[] {
                JwtClaimTypes.Subject,
                JwtClaimTypes.ClientId
            };

            foreach (var claim in claimsToValidate)
            {
                var claimValue = tokenValidationResult.Claims.SingleOrDefault(x => x.Type == claim)?.Value;
                if (string.IsNullOrWhiteSpace(claimValue))
                {
                    return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken, $"Access token must contain the '{claim}' claim."));
                }
            }
            // Get 'code' parameter and retrieve it from the store.
            var code = parameters.Get(RegistrationRequestParameters.Code);

            if (string.IsNullOrWhiteSpace(code))
            {
                return(Error(OidcConstants.TokenErrors.InvalidGrant, $"Parameter '{nameof(RegistrationRequestParameters.Code)}' is not specified."));
            }
            var authorizationCode = await CodeChallengeStore.GetAuthorizationCode(code);

            if (authorizationCode == null)
            {
                return(Error(OidcConstants.TokenErrors.InvalidGrant, "Authorization code is invalid."));
            }
            // Validate that the consumer specified all required parameters.
            var parametersToValidate = new List <string> {
                RegistrationRequestParameters.CodeSignature,
                RegistrationRequestParameters.CodeVerifier,
                RegistrationRequestParameters.DeviceId,
                RegistrationRequestParameters.DevicePlatform
            };

            if (authorizationCode.InteractionMode == InteractionMode.Fingerprint)
            {
                parametersToValidate.Add(RegistrationRequestParameters.PublicKey);
            }
            if (authorizationCode.InteractionMode == InteractionMode.Pin)
            {
                parametersToValidate.Add(RegistrationRequestParameters.Pin);
            }
            var otpAuthenticatedValue = tokenValidationResult.Claims.FirstOrDefault(x => x.Type == BasicClaimTypes.OtpAuthenticated)?.Value;
            var otpAuthenticated      = !string.IsNullOrWhiteSpace(otpAuthenticatedValue) && bool.Parse(otpAuthenticatedValue);

            if (!otpAuthenticated)
            {
                parametersToValidate.Add(RegistrationRequestParameters.OtpCode);
            }
            foreach (var parameter in parametersToValidate)
            {
                var parameterValue = parameters.Get(parameter);
                if (string.IsNullOrWhiteSpace(parameterValue))
                {
                    return(Error(OidcConstants.TokenErrors.InvalidGrant, $"Parameter '{parameter}' is not specified."));
                }
            }
            var isValidPlatform = Enum.TryParse(typeof(DevicePlatform), parameters.Get(RegistrationRequestParameters.DevicePlatform), out var platform);

            if (!isValidPlatform)
            {
                return(Error(OidcConstants.TokenErrors.InvalidRequest, $"Parameter '{nameof(RegistrationRequestParameters.DevicePlatform)}' does not have a valid value."));
            }
            // Load client and validate that it allows the 'password' flow.
            var client = await LoadClient(tokenValidationResult);

            if (client == null)
            {
                return(Error(OidcConstants.AuthorizeErrors.UnauthorizedClient, $"Client is unknown or not enabled."));
            }
            if (client.AllowedGrantTypes.Except(Constants.RequiredGrantTypes).Any())
            {
                return(Error(OidcConstants.AuthorizeErrors.UnauthorizedClient, $"Client not authorized any of the following grant types: {string.Join(", ", Constants.RequiredGrantTypes)}"));
            }
            // Validate authorization code against code verifier given by the client.
            var codeVerifier = parameters.Get(RegistrationRequestParameters.CodeVerifier);
            var authorizationCodeValidationResult = await ValidateAuthorizationCode(code, authorizationCode, codeVerifier, parameters.Get(RegistrationRequestParameters.DeviceId), client);

            if (authorizationCodeValidationResult.IsError)
            {
                return(Error(authorizationCodeValidationResult.Error, authorizationCodeValidationResult.ErrorDescription));
            }
            // Validate given public key against signature for fingerprint.
            string publicKey = null;

            if (authorizationCode.InteractionMode == InteractionMode.Fingerprint)
            {
                publicKey = parameters.Get(RegistrationRequestParameters.PublicKey);
                var codeSignature             = parameters.Get(RegistrationRequestParameters.CodeSignature);
                var publicKeyValidationResult = ValidateSignature(publicKey, code, codeSignature);
                if (publicKeyValidationResult.IsError)
                {
                    return(Error(publicKeyValidationResult.Error, publicKeyValidationResult.ErrorDescription));
                }
            }
            // Find requested scopes.
            var requestedScopes = tokenValidationResult.Claims.Where(claim => claim.Type == JwtClaimTypes.Scope).Select(claim => claim.Value).ToList();
            // Create principal from incoming access token excluding protocol claims.
            var claims    = tokenValidationResult.Claims.Where(x => !Constants.ProtocolClaimsFilter.Contains(x.Type));
            var principal = Principal.Create("TrustedDevice", claims.ToArray());
            var userId    = tokenValidationResult.Claims.Single(x => x.Type == JwtClaimTypes.Subject).Value;

            // Validate OTP code, if needed.
            if (!otpAuthenticated)
            {
                var totpResult = await TotpService.Verify(
                    principal : principal,
                    code : parameters.Get(RegistrationRequestParameters.OtpCode),
                    purpose : Constants.TrustedDeviceOtpPurpose(userId, authorizationCode.DeviceId)
                    );

                if (!totpResult.Success)
                {
                    return(Error(totpResult.Error));
                }
            }
            // Finally return result.
            return(new CompleteRegistrationRequestValidationResult {
                IsError = false,
                Client = client,
                DeviceId = authorizationCode.DeviceId,
                DeviceName = parameters.Get(RegistrationRequestParameters.DeviceName),
                DevicePlatform = (DevicePlatform)platform,
                InteractionMode = authorizationCode.InteractionMode,
                Pin = parameters.Get(RegistrationRequestParameters.Pin),
                Principal = principal,
                PublicKey = publicKey,
                RequestedScopes = requestedScopes,
                UserId = userId
            });
        }
        private async Task <ResponseValidationResult> ProcessCodeFlowResponseAsync(
            AuthorizeResponse authorizeResponse,
            AuthorizeState state,
            Parameters backChannelParameters,
            CancellationToken cancellationToken)
        {
            _logger.LogTrace("ProcessCodeFlowResponseAsync");

            //////////////////////////////////////////////////////
            // process back-channel response
            //////////////////////////////////////////////////////

            // redeem code for tokens
            var tokenResponse = await RedeemCodeAsync(authorizeResponse.Code, state, backChannelParameters, cancellationToken);

            if (tokenResponse.IsError)
            {
                return(new ResponseValidationResult($"Error redeeming code: {tokenResponse.Error ?? "no error code"} / {tokenResponse.ErrorDescription ?? "no description"}"));
            }
            if (tokenResponse.HttpStatusCode != HttpStatusCode.OK)
            {
                return(new ResponseValidationResult($"Error redeeming code: {tokenResponse.Raw}"));
            }

            // validate token response
            var tokenResponseValidationResult = await ValidateTokenResponseAsync(tokenResponse, state, requireIdentityToken : false, cancellationToken : cancellationToken);

            if (tokenResponseValidationResult.IsError)
            {
                return(new ResponseValidationResult($"Error validating token response: {tokenResponseValidationResult.Error}"));
            }

            return(new ResponseValidationResult
            {
                AuthorizeResponse = authorizeResponse,
                TokenResponse = tokenResponse,
                User = tokenResponseValidationResult?.IdentityTokenValidationResult?.User ?? Principal.Create(_options.Authority)
            });
        }