Exemplo n.º 1
0
    /// <inheritdoc/>
    public async Task <TokenValidationResult> ValidateRefreshTokenAsync(string tokenHandle, Client client)
    {
        var result = await Inner.ValidateRefreshTokenAsync(tokenHandle, client);

        if (!result.IsError)
        {
            var valid = await SessionCoordinationService.ValidateSessionAsync(new SessionValidationRequest
            {
                SubjectId = result.RefreshToken.SubjectId,
                SessionId = result.RefreshToken.SessionId,
                Client    = result.Client,
                Type      = SessionValidationType.RefreshToken
            });

            if (!valid)
            {
                result = TokenValidationError;
            }
        }

        return(result);
    }
    public async Task <TokenValidationResult> ValidateAccessTokenAsync(string token, string expectedScope = null)
    {
        using var activity = Tracing.BasicActivitySource.StartActivity("TokenValidator.ValidateAccessToken");

        _logger.LogTrace("Start access token validation");

        _log.ExpectedScope    = expectedScope;
        _log.ValidateLifetime = true;

        TokenValidationResult result;

        if (token.Contains("."))
        {
            if (token.Length > _options.InputLengthRestrictions.Jwt)
            {
                _logger.LogError("JWT too long");

                return(new TokenValidationResult
                {
                    IsError = true,
                    Error = OidcConstants.ProtectedResourceErrors.InvalidToken,
                    ErrorDescription = "Token too long"
                });
            }

            _log.AccessTokenType = AccessTokenType.Jwt.ToString();
            result = await ValidateJwtAsync(
                token,
                await _keys.GetValidationKeysAsync());
        }
        else
        {
            if (token.Length > _options.InputLengthRestrictions.TokenHandle)
            {
                _logger.LogError("token handle too long");

                return(new TokenValidationResult
                {
                    IsError = true,
                    Error = OidcConstants.ProtectedResourceErrors.InvalidToken,
                    ErrorDescription = "Token too long"
                });
            }

            _log.AccessTokenType = AccessTokenType.Reference.ToString();
            result = await ValidateReferenceAccessTokenAsync(token);
        }

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

        if (result.IsError)
        {
            return(result);
        }

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

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

            if (client == null)
            {
                _logger.LogError("Client deleted or disabled: {clientId}", clientClaim.Value);

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

                return(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());

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

            var isActiveCtx = new IsActiveContext(principal, result.Client,
                                                  IdentityServerConstants.ProfileIsActiveCallers.AccessTokenValidation);
            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);
            }

            var sub = subClaim.Value;
            var sid = principal.FindFirstValue("sid");
            if (sid != null)
            {
                var sessionResult = await _sessionCoordinationService.ValidateSessionAsync(new SessionValidationRequest
                {
                    SubjectId = sub,
                    SessionId = sid,
                    Client    = result.Client,
                    Type      = SessionValidationType.AccessToken
                });

                if (!sessionResult)
                {
                    _logger.LogError("Server-side session invalid for subject Id {subjectId} and session Id {sessionId}.", sub, sid);
                    return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken));
                }
            }
        }

        // check expected scope(s)
        if (expectedScope.IsPresent())
        {
            var scope = result.Claims.FirstOrDefault(c =>
                                                     c.Type == JwtClaimTypes.Scope && c.Value == expectedScope);
            if (scope == null)
            {
                LogError($"Checking for expected scope {expectedScope} failed");
                return(Invalid(OidcConstants.ProtectedResourceErrors.InsufficientScope));
            }
        }

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

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

        // add claims again after custom validation
        _log.Claims = customResult.Claims.ToClaimsDictionary();

        LogSuccess();
        return(customResult);
    }