Exemplo n.º 1
0
        private async Task <bool> TryRevokeTokensAsync([NotNull] AuthenticationTicket ticket)
        {
            // Note: if the authorization identifier is null, return true as no tokens need to be revoked.
            var identifier = ticket.GetInternalAuthorizationId();

            if (string.IsNullOrEmpty(identifier))
            {
                return(true);
            }

            var result = true;

            foreach (var token in await _tokenManager.FindByAuthorizationIdAsync(identifier))
            {
                // Don't change the status of the token used in the token request.
                if (string.Equals(ticket.GetInternalTokenId(),
                                  await _tokenManager.GetIdAsync(token), StringComparison.Ordinal))
                {
                    continue;
                }

                result &= await TryRevokeTokenAsync(token);
            }

            return(result);
        }
Exemplo n.º 2
0
        private async Task <bool> TryRevokeAuthorizationAsync([NotNull] AuthenticationTicket ticket)
        {
            // Note: if the authorization identifier or the authorization itself
            // cannot be found, return true as the authorization doesn't need
            // to be revoked if it doesn't exist or is already invalid.
            var identifier = ticket.GetInternalAuthorizationId();

            if (string.IsNullOrEmpty(identifier))
            {
                return(true);
            }

            var authorization = await _authorizationManager.FindByIdAsync(identifier);

            if (authorization == null)
            {
                return(true);
            }

            try
            {
                // Note: the request cancellation token is deliberately not used here to ensure the caller
                // cannot prevent this operation from being executed by resetting the TCP connection.
                await _authorizationManager.RevokeAsync(authorization);

                _logger.LogInformation("The authorization '{Identifier}' was automatically revoked.", identifier);

                return(true);
            }

            catch (OpenIddictExceptions.ConcurrencyException exception)
            {
                _logger.LogDebug(exception, "A concurrency exception occurred while trying to revoke the authorization " +
                                 "associated with the token '{Identifier}'.", identifier);

                return(false);
            }

            catch (Exception exception)
            {
                _logger.LogWarning(exception, "An exception occurred while trying to revoke the authorization " +
                                   "associated with the token '{Identifier}'.", identifier);

                return(false);
            }
        }
Exemplo n.º 3
0
        public static async Task <AuthenticationTicket> CreateAuthenticationTicket(
            OpenIddictApplicationManager <BTCPayOpenIdClient> applicationManager,
            OpenIddictAuthorizationManager <BTCPayOpenIdAuthorization> authorizationManager,
            IdentityOptions identityOptions,
            SignInManager <ApplicationUser> signInManager,
            OpenIdConnectRequest request,
            ApplicationUser user,
            AuthenticationProperties properties = null)
        {
            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await signInManager.CreateUserPrincipalAsync(user);

            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal, properties,
                                                  OpenIddictServerDefaults.AuthenticationScheme);

            if (!request.IsAuthorizationCodeGrantType() && !request.IsRefreshTokenGrantType())
            {
                ticket.SetScopes(request.GetScopes());
            }
            else if (request.IsAuthorizationCodeGrantType() &&
                     string.IsNullOrEmpty(ticket.GetInternalAuthorizationId()))
            {
                var app = await applicationManager.FindByClientIdAsync(request.ClientId);

                var authorizationId = await IsUserAuthorized(authorizationManager, request, user.Id, app.Id);

                if (!string.IsNullOrEmpty(authorizationId))
                {
                    ticket.SetInternalAuthorizationId(authorizationId);
                }
            }

            foreach (var claim in ticket.Principal.Claims)
            {
                claim.SetDestinations(GetDestinations(identityOptions, claim, ticket));
            }

            return(ticket);
        }
Exemplo n.º 4
0
        private async Task <string> CreateTokenAsync(
            [NotNull] string type, [NotNull] AuthenticationTicket ticket,
            [NotNull] OpenIddictServerOptions options,
            [NotNull] OpenIdConnectRequest request,
            [NotNull] ISecureDataFormat <AuthenticationTicket> format)
        {
            Debug.Assert(!(options.DisableTokenStorage && options.UseReferenceTokens),
                         "Token storage cannot be disabled when using reference tokens.");

            Debug.Assert(type == OpenIdConnectConstants.TokenUsages.AccessToken ||
                         type == OpenIdConnectConstants.TokenUsages.AuthorizationCode ||
                         type == OpenIdConnectConstants.TokenUsages.RefreshToken,
                         "Only authorization codes, access and refresh tokens should be created using this method.");

            // When sliding expiration is disabled, the expiration date of generated refresh tokens is fixed
            // and must exactly match the expiration date of the refresh token used in the token request.
            if (request.IsTokenRequest() && request.IsRefreshTokenGrantType() &&
                !options.UseSlidingExpiration && type == OpenIdConnectConstants.TokenUsages.RefreshToken)
            {
                var properties = request.GetProperty <AuthenticationTicket>(
                    OpenIddictConstants.Properties.AuthenticationTicket)?.Properties;
                Debug.Assert(properties != null, "The authentication properties shouldn't be null.");

                ticket.Properties.ExpiresUtc = properties.ExpiresUtc;
            }

            if (options.DisableTokenStorage)
            {
                return(null);
            }

            var descriptor = new OpenIddictTokenDescriptor
            {
                AuthorizationId = ticket.GetInternalAuthorizationId(),
                CreationDate    = ticket.Properties.IssuedUtc,
                ExpirationDate  = ticket.Properties.ExpiresUtc,
                Principal       = ticket.Principal,
                Status          = OpenIddictConstants.Statuses.Valid,
                Subject         = ticket.Principal.GetClaim(OpenIddictConstants.Claims.Subject),
                Type            = type
            };

            foreach (var property in ticket.Properties.Items)
            {
                descriptor.Properties.Add(property);
            }

            // When reference tokens are enabled or when the token is an authorization code or a
            // refresh token, remove the unnecessary properties from the authentication ticket.
            if (options.UseReferenceTokens ||
                (type == OpenIdConnectConstants.TokenUsages.AuthorizationCode ||
                 type == OpenIdConnectConstants.TokenUsages.RefreshToken))
            {
                ticket.Properties.IssuedUtc = ticket.Properties.ExpiresUtc = null;
                ticket.RemoveProperty(OpenIddictConstants.Properties.InternalAuthorizationId)
                .RemoveProperty(OpenIddictConstants.Properties.InternalTokenId);
            }

            // If reference tokens are enabled, create a new entry for
            // authorization codes, refresh tokens and access tokens.
            if (options.UseReferenceTokens)
            {
                // Note: the data format is automatically replaced at startup time to ensure
                // that encrypted tokens stored in the database cannot be considered as
                // valid tokens if the developer decides to disable reference tokens support.
                descriptor.Payload = format.Protect(ticket);

                // Generate a new crypto-secure random identifier that will be
                // substituted to the ciphertext returned by the data format.
                var bytes = new byte[256 / 8];
                options.RandomNumberGenerator.GetBytes(bytes);

                // Note: the default token manager automatically obfuscates the
                // reference identifier so it can be safely stored in the databse.
                descriptor.ReferenceId = Base64UrlEncoder.Encode(bytes);
            }

            // Otherwise, only create a token metadata entry for authorization codes and refresh tokens.
            else if (type != OpenIdConnectConstants.TokenUsages.AuthorizationCode &&
                     type != OpenIdConnectConstants.TokenUsages.RefreshToken)
            {
                return(null);
            }

            // If the client application is known, associate it with the token.
            if (!string.IsNullOrEmpty(request.ClientId))
            {
                var application = await _applicationManager.FindByClientIdAsync(request.ClientId);

                if (application == null)
                {
                    throw new InvalidOperationException("The application entry cannot be found in the database.");
                }

                descriptor.ApplicationId = await _applicationManager.GetIdAsync(application);
            }

            // If a null value was returned by CreateAsync(), return immediately.

            // Note: the request cancellation token is deliberately not used here to ensure the caller
            // cannot prevent this operation from being executed by resetting the TCP connection.
            var token = await _tokenManager.CreateAsync(descriptor);

            if (token == null)
            {
                return(null);
            }

            // Throw an exception if the token identifier can't be resolved.
            var identifier = await _tokenManager.GetIdAsync(token);

            if (string.IsNullOrEmpty(identifier))
            {
                throw new InvalidOperationException("The unique key associated with a refresh token cannot be null or empty.");
            }

            // Dynamically set the creation and expiration dates.
            ticket.Properties.IssuedUtc  = descriptor.CreationDate;
            ticket.Properties.ExpiresUtc = descriptor.ExpirationDate;

            // Restore the token/authorization identifiers using the identifiers attached with the database entry.
            ticket.SetInternalAuthorizationId(descriptor.AuthorizationId)
            .SetInternalTokenId(identifier);

            if (options.UseReferenceTokens)
            {
                _logger.LogTrace("A new reference token was successfully generated and persisted " +
                                 "in the database: {Token} ; {Claims} ; {Properties}.",
                                 descriptor.ReferenceId, ticket.Principal.Claims, ticket.Properties.Items);

                return(descriptor.ReferenceId);
            }

            return(null);
        }