Example #1
0
        public override async Task HandleIntrospectionRequest([NotNull] HandleIntrospectionRequestContext context)
        {
            var services = context.HttpContext.RequestServices.GetRequiredService <OpenIddictServices <TUser, TApplication> >();
            var options  = context.HttpContext.RequestServices.GetRequiredService <IOptions <IdentityOptions> >();

            // If the user manager doesn't support security
            // stamps, skip the additional validation logic.
            if (!services.Users.SupportsUserSecurityStamp)
            {
                return;
            }

            var principal = context.Ticket?.Principal;

            Debug.Assert(principal != null);

            var user = await services.Users.GetUserAsync(principal);

            if (user == null)
            {
                context.Active = false;

                return;
            }

            var identifier = principal.GetClaim(options.Value.ClaimsIdentity.SecurityStampClaimType);

            if (!string.IsNullOrEmpty(identifier) &&
                !string.Equals(identifier, await services.Users.GetSecurityStampAsync(user), StringComparison.Ordinal))
            {
                context.Active = false;

                return;
            }
        }
Example #2
0
        public override async Task HandleIntrospectionRequest([NotNull] HandleIntrospectionRequestContext context)
        {
            var services = context.HttpContext.RequestServices.GetRequiredService <OpenIddictServices <TUser, TApplication, TAuthorization, TScope, TToken> >();

            Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");
            Debug.Assert(!string.IsNullOrEmpty(context.Request.ClientId), "The client_id parameter shouldn't be null.");

            // Note: the OpenID Connect server middleware allows authorized presenters (e.g relying parties) to introspect access tokens
            // but OpenIddict uses a stricter policy that only allows resource servers to use the introspection endpoint, unless the ticket
            // doesn't have any audience: in this case, the caller is allowed to introspect the token even if it's not listed as a valid audience.
            if (context.Ticket.IsAccessToken() && context.Ticket.HasAudience() && !context.Ticket.HasAudience(context.Request.ClientId))
            {
                services.Logger.LogWarning("The client application '{ClientId}' is not allowed to introspect the access " +
                                           "token '{Identifier}' because it's not listed as a valid audience.",
                                           context.Request.ClientId, context.Ticket.GetTicketId());

                context.Active = false;

                return;
            }

            var user = await services.Users.GetUserAsync(context.Ticket.Principal);

            if (user == null)
            {
                services.Logger.LogInformation("The token {Identifier} was declared as inactive because the " +
                                               "corresponding user ({Username}) was not found in the database.",
                                               context.Ticket.GetTicketId(), services.Users.GetUserName(context.Ticket.Principal));

                context.Active = false;

                return;
            }

            // When the received ticket is revocable, ensure it is still valid.
            if (context.Ticket.IsAuthorizationCode() || context.Ticket.IsRefreshToken())
            {
                // Retrieve the token from the database using the unique identifier stored in the authentication ticket:
                // if the corresponding entry cannot be found, return Active = false to indicate that is is no longer valid.
                var token = await services.Tokens.FindByIdAsync(context.Ticket.GetTicketId());

                if (token == null)
                {
                    services.Logger.LogInformation("The token {Identifier} was declared as inactive because " +
                                                   "it was revoked.", context.Ticket.GetTicketId());

                    context.Active = false;

                    return;
                }
            }
        }
Example #3
0
        public override async Task HandleIntrospectionRequest([NotNull] HandleIntrospectionRequestContext context)
        {
            var options = (OpenIddictOptions)context.Options;

            Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");
            Debug.Assert(!string.IsNullOrEmpty(context.Request.ClientId), "The client_id parameter shouldn't be null.");

            var identifier = context.Ticket.GetProperty(OpenIdConnectConstants.Properties.TokenId);

            Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");

            // Note: the OpenID Connect server middleware allows authorized presenters (e.g relying parties) to introspect access tokens
            // but OpenIddict uses a stricter policy that only allows resource servers to use the introspection endpoint, unless the ticket
            // doesn't have any audience: in this case, the caller is allowed to introspect the token even if it's not listed as a valid audience.
            if (context.Ticket.IsAccessToken() && context.Ticket.HasAudience() && !context.Ticket.HasAudience(context.Request.ClientId))
            {
                Logger.LogWarning("The client application '{ClientId}' is not allowed to introspect the access " +
                                  "token '{Identifier}' because it's not listed as a valid audience.",
                                  context.Request.ClientId, identifier);

                context.Active = false;

                return;
            }

            if (options.DisableTokenRevocation)
            {
                return;
            }

            // When the received ticket is revocable, ensure it is still valid.
            if (options.UseReferenceTokens || context.Ticket.IsAuthorizationCode() || context.Ticket.IsRefreshToken())
            {
                // Retrieve the token from the database using the unique identifier stored in the authentication ticket:
                // if the corresponding entry cannot be found, return Active = false to indicate that is is no longer valid.
                var token = await Tokens.FindByIdAsync(identifier, context.HttpContext.RequestAborted);

                if (token == null || !await Tokens.IsValidAsync(token, context.HttpContext.RequestAborted))
                {
                    Logger.LogInformation("The token '{Identifier}' was declared as inactive because it was revoked.", identifier);

                    context.Active = false;

                    return;
                }
            }
        }
        public override async Task HandleIntrospectionRequest([NotNull] HandleIntrospectionRequestContext context)
        {
            var options = (OpenIddictOptions)context.Options;

            Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");
            Debug.Assert(!string.IsNullOrEmpty(context.Request.ClientId), "The client_id parameter shouldn't be null.");

            var identifier = context.Ticket.GetTokenId();

            Debug.Assert(!string.IsNullOrEmpty(identifier), "The authentication ticket should contain a token identifier.");

            if (!context.Ticket.IsAccessToken())
            {
                Logger.LogError("The token '{Identifier}' is not an access token and thus cannot be introspected.", identifier);

                context.Active = false;

                return;
            }

            // Note: the OpenID Connect server middleware allows authorized presenters (e.g relying parties) to introspect
            // tokens but OpenIddict uses a stricter policy that only allows resource servers to use the introspection endpoint.
            // For that, an error is automatically returned if no explicit audience is attached to the authentication ticket.
            if (!context.Ticket.HasAudience())
            {
                Logger.LogError("The token '{Identifier}' doesn't have any audience attached " +
                                "and cannot be introspected. To add an audience, use the " +
                                "'ticket.SetResources(...)' extension when creating the ticket.", identifier);

                context.Active = false;

                return;
            }

            if (!context.Ticket.HasAudience(context.Request.ClientId))
            {
                Logger.LogError("The client application '{ClientId}' is not allowed to introspect the access " +
                                "token '{Identifier}' because it's not listed as a valid audience.",
                                context.Request.ClientId, identifier);

                context.Active = false;

                return;
            }

            // If the received token is not a reference access token,
            // skip the additional reference token validation checks.
            if (!options.UseReferenceTokens)
            {
                return;
            }

            // Retrieve the token from the request properties. If it's marked as invalid, return active = false.
            var token = context.Request.GetProperty <TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");

            Debug.Assert(token != null, "The token shouldn't be null.");

            if (!await Tokens.IsValidAsync(token))
            {
                Logger.LogInformation("The token '{Identifier}' was declared as inactive because it was revoked.", identifier);

                context.Active = false;

                return;
            }
        }
        public override async Task HandleIntrospectionRequest([NotNull] HandleIntrospectionRequestContext context)
        {
            var options = (OpenIddictServerOptions)context.Options;

            Debug.Assert(context.Ticket != null, "The authentication ticket shouldn't be null.");
            Debug.Assert(!string.IsNullOrEmpty(context.Request.ClientId), "The client_id parameter shouldn't be null.");

            var identifier = context.Ticket.GetProperty(OpenIddictConstants.Properties.InternalTokenId);

            Debug.Assert(!string.IsNullOrEmpty(identifier), "The authentication ticket should contain a token identifier.");

            if (!context.Ticket.IsAccessToken())
            {
                _logger.LogError("The token '{Identifier}' is not an access token and thus cannot be introspected.", identifier);

                context.Active = false;

                return;
            }

            // Note: the OpenID Connect server middleware allows authorized presenters (e.g relying parties) to introspect
            // tokens but OpenIddict uses a stricter policy that only allows resource servers to use the introspection endpoint.
            // For that, an error is automatically returned if no explicit audience is attached to the authentication ticket.
            if (!context.Ticket.HasAudience())
            {
                _logger.LogError("The token '{Identifier}' doesn't have any audience attached " +
                                 "and cannot be introspected. To add an audience, use the " +
                                 "'ticket.SetResources(...)' extension when creating the ticket.", identifier);

                context.Active = false;

                return;
            }

            if (!context.Ticket.HasAudience(context.Request.ClientId))
            {
                _logger.LogError("The client application '{ClientId}' is not allowed to introspect the access " +
                                 "token '{Identifier}' because it's not listed as a valid audience.",
                                 context.Request.ClientId, identifier);

                context.Active = false;

                return;
            }

            // If an authorization was attached to the access token, ensure it is still valid.
            if (!options.DisableAuthorizationStorage &&
                context.Ticket.HasProperty(OpenIddictConstants.Properties.InternalAuthorizationId))
            {
                var authorization = await _authorizationManager.FindByIdAsync(
                    context.Ticket.GetProperty(OpenIddictConstants.Properties.InternalAuthorizationId));

                if (authorization == null || !await _authorizationManager.IsValidAsync(authorization))
                {
                    _logger.LogError("The token '{Identifier}' was declared as inactive because " +
                                     "the associated authorization was no longer valid.", identifier);

                    context.Active = false;

                    return;
                }
            }

            // If the received token is a reference access token - i.e a token for
            // which an entry exists in the database - ensure it is still valid.
            if (options.UseReferenceTokens)
            {
                // Retrieve the token from the request properties. If it's marked as invalid, return active = false.
                var token = context.Request.GetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}");
                Debug.Assert(token != null, "The token shouldn't be null.");

                if (!await _tokenManager.IsValidAsync(token))
                {
                    _logger.LogInformation("The token '{Identifier}' was declared as inactive because it was revoked.", identifier);

                    context.Active = false;

                    return;
                }
            }

            await _eventService.PublishAsync(new OpenIddictServerEvents.HandleIntrospectionRequest(context));
        }
 public Task HandleIntrospectionRequest(HandleIntrospectionRequestContext context)
 {
     throw new NotImplementedException();
 }