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); } }
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); }
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)); }
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)); }
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); } }