private async Task <bool> TryExtendTokenAsync(
            [NotNull] object token, [NotNull] AuthenticationTicket ticket, [NotNull] OpenIddictServerOptions options)
        {
            var identifier = ticket.GetTokenId();

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

            try
            {
                // Compute the new expiration date of the refresh token.
                var date = options.SystemClock.UtcNow;
                date += ticket.GetRefreshTokenLifetime() ?? options.RefreshTokenLifetime;

                // 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 _tokenManager.ExtendAsync(token, date);

                _logger.LogInformation("The expiration date of the refresh token '{Identifier}' " +
                                       "was automatically updated: {Date}.", identifier, date);

                return(true);
            }

            catch (Exception exception)
            {
                _logger.LogDebug(exception, "An exception occurred while trying to update the " +
                                 "expiration date of the token '{Identifier}'.", identifier);

                return(false);
            }
        }
예제 #2
0
        private async Task <string> SerializeRefreshTokenAsync(
            ClaimsPrincipal principal, AuthenticationProperties properties,
            OpenIdConnectRequest request, OpenIdConnectResponse response)
        {
            // Note: claims in refresh tokens are never filtered as they are supposed to be opaque:
            // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring
            // that subsequent access and identity tokens are correctly filtered.

            // Create a new ticket containing the updated properties.
            var ticket = new AuthenticationTicket(principal, properties, Scheme.Name);

            ticket.Properties.IssuedUtc = Options.SystemClock.UtcNow;

            // Only set the expiration date if a lifetime was specified in either the ticket or the options.
            var lifetime = ticket.GetRefreshTokenLifetime() ?? Options.RefreshTokenLifetime;

            if (lifetime.HasValue)
            {
                ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc + lifetime.Value;
            }

            // Associate a random identifier with the refresh token.
            ticket.SetTokenId(Guid.NewGuid().ToString());

            // Remove the unwanted properties from the authentication ticket.
            ticket.RemoveProperty(OpenIdConnectConstants.Properties.AuthorizationCodeLifetime)
            .RemoveProperty(OpenIdConnectConstants.Properties.CodeChallenge)
            .RemoveProperty(OpenIdConnectConstants.Properties.CodeChallengeMethod)
            .RemoveProperty(OpenIdConnectConstants.Properties.Nonce)
            .RemoveProperty(OpenIdConnectConstants.Properties.OriginalRedirectUri)
            .RemoveProperty(OpenIdConnectConstants.Properties.TokenUsage);

            var notification = new SerializeRefreshTokenContext(Context, Scheme, Options, request, response, ticket)
            {
                DataFormat = Options.RefreshTokenFormat
            };

            await Provider.SerializeRefreshToken(notification);

            if (notification.IsHandled || !string.IsNullOrEmpty(notification.RefreshToken))
            {
                return(notification.RefreshToken);
            }

            if (notification.DataFormat == null)
            {
                throw new InvalidOperationException("A data formatter must be provided.");
            }

            var result = notification.DataFormat.Protect(ticket);

            Logger.LogTrace("A new refresh token was successfully generated using the " +
                            "specified data format: {Token} ; {Claims} ; {Properties}.",
                            result, ticket.Principal.Claims, ticket.Properties.Items);

            return(result);
        }
예제 #3
0
        public void GetRefreshTokenLifetime_ReturnsExpectedResult(string lifetime)
        {
            // Arrange
            var ticket = new AuthenticationTicket(
                new ClaimsIdentity(),
                new AuthenticationProperties());

            ticket.Properties.Dictionary[OpenIdConnectConstants.Properties.RefreshTokenLifetime] = lifetime;

            // Act and assert
            Assert.Equal(lifetime, ticket.GetRefreshTokenLifetime()?.ToString("c", CultureInfo.InvariantCulture));
        }
        private async Task <string> SerializeRefreshTokenAsync(
            ClaimsPrincipal principal, AuthenticationProperties properties,
            OpenIdConnectRequest request, OpenIdConnectResponse response)
        {
            // Note: claims in refresh tokens are never filtered as they are supposed to be opaque:
            // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring
            // that subsequent access and identity tokens are correctly filtered.

            // Create a new ticket containing the updated properties.
            var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);

            ticket.Properties.IssuedUtc  = Options.SystemClock.UtcNow;
            ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc +
                                           (ticket.GetRefreshTokenLifetime() ?? Options.RefreshTokenLifetime);

            ticket.SetUsage(OpenIdConnectConstants.Usages.RefreshToken);

            // Associate a random identifier with the refresh token.
            ticket.SetTicketId(Guid.NewGuid().ToString());

            // Remove the unwanted properties from the authentication ticket.
            ticket.RemoveProperty(OpenIdConnectConstants.Properties.AuthorizationCodeLifetime)
            .RemoveProperty(OpenIdConnectConstants.Properties.ClientId)
            .RemoveProperty(OpenIdConnectConstants.Properties.CodeChallenge)
            .RemoveProperty(OpenIdConnectConstants.Properties.CodeChallengeMethod)
            .RemoveProperty(OpenIdConnectConstants.Properties.Nonce)
            .RemoveProperty(OpenIdConnectConstants.Properties.RedirectUri);

            var notification = new SerializeRefreshTokenContext(Context, Options, request, response, ticket)
            {
                DataFormat = Options.RefreshTokenFormat
            };

            await Options.Provider.SerializeRefreshToken(notification);

            if (notification.HandledResponse || !string.IsNullOrEmpty(notification.RefreshToken))
            {
                return(notification.RefreshToken);
            }

            else if (notification.Skipped)
            {
                return(null);
            }

            if (!ReferenceEquals(ticket, notification.Ticket))
            {
                throw new InvalidOperationException("The authentication ticket cannot be replaced.");
            }

            return(notification.DataFormat?.Protect(ticket));
        }
예제 #5
0
        private async Task <bool> TryExtendRefreshTokenAsync(
            [NotNull] object token, [NotNull] AuthenticationTicket ticket, [NotNull] OpenIddictServerOptions options)
        {
            var identifier = ticket.GetProperty(OpenIddictConstants.Properties.InternalTokenId);

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

            try
            {
                // Compute the new expiration date of the refresh token.
                var lifetime = ticket.GetRefreshTokenLifetime() ?? options.RefreshTokenLifetime;
                if (lifetime != null)
                {
                    // 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 date = options.SystemClock.UtcNow + lifetime.Value;
                    await _tokenManager.ExtendAsync(token, date);

                    _logger.LogInformation("The expiration date of the refresh token '{Identifier}' " +
                                           "was automatically updated: {Date}.", identifier, date);
                }

                else if (await _tokenManager.GetExpirationDateAsync(token) != null)
                {
                    // 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 _tokenManager.ExtendAsync(token, date : null);

                    _logger.LogInformation("The expiration date of the refresh token '{Identifier}' was removed.", identifier);
                }

                return(true);
            }

            catch (OpenIddictException exception) when(exception.Reason == OpenIddictConstants.Exceptions.ConcurrencyError)
            {
                _logger.LogDebug(exception, "A concurrency exception occurred while trying to update the " +
                                 "expiration date of the token '{Identifier}'.", identifier);

                return(false);
            }

            catch (Exception exception)
            {
                _logger.LogWarning(exception, "An exception occurred while trying to update the " +
                                   "expiration date of the token '{Identifier}'.", identifier);

                return(false);
            }
        }
        private async Task <string> SerializeRefreshTokenAsync(
            ClaimsIdentity identity, AuthenticationProperties properties,
            OpenIdConnectRequest request, OpenIdConnectResponse response)
        {
            // Note: claims in refresh tokens are never filtered as they are supposed to be opaque:
            // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring
            // that subsequent access and identity tokens are correctly filtered.

            // Create a new ticket containing the updated properties.
            var ticket = new AuthenticationTicket(identity, properties);

            ticket.Properties.IssuedUtc  = Options.SystemClock.UtcNow;
            ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc +
                                           (ticket.GetRefreshTokenLifetime() ?? Options.RefreshTokenLifetime);

            ticket.SetUsage(OpenIdConnectConstants.Usages.RefreshToken);

            // Associate a random identifier with the refresh token.
            ticket.SetTicketId(Guid.NewGuid().ToString());

            // By default, add the client_id to the list of the
            // presenters allowed to use the refresh token.
            if (!string.IsNullOrEmpty(request.ClientId))
            {
                ticket.SetPresenters(request.ClientId);
            }

            var notification = new SerializeRefreshTokenContext(Context, Options, request, response, ticket)
            {
                DataFormat = Options.RefreshTokenFormat
            };

            await Options.Provider.SerializeRefreshToken(notification);

            if (notification.HandledResponse || !string.IsNullOrEmpty(notification.RefreshToken))
            {
                return(notification.RefreshToken);
            }

            else if (notification.Skipped)
            {
                return(null);
            }

            return(notification.DataFormat?.Protect(ticket));
        }
예제 #7
0
        private async Task <bool> TryExtendTokenAsync(
            [NotNull] AuthenticationTicket ticket, [NotNull] HttpContext context, [NotNull] OpenIddictOptions options)
        {
            var identifier = ticket.GetTokenId();

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

            var token = await Tokens.FindByIdAsync(identifier, context.RequestAborted);

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

            try
            {
                // Compute the new expiration date of the refresh token.
                var date = options.SystemClock.UtcNow;
                date += ticket.GetRefreshTokenLifetime() ?? options.RefreshTokenLifetime;

                await Tokens.ExtendAsync(token, date, context.RequestAborted);

                Logger.LogInformation("The expiration date of the refresh token '{Identifier}' " +
                                      "was automatically updated: {Date}.", identifier, date);

                return(true);
            }

            catch (Exception exception)
            {
                Logger.LogWarning(exception, "An exception occurred while trying to update the " +
                                  "expiration date of the token '{Identifier}'.", identifier);

                return(false);
            }
        }