Browse Source

Make authorization codes reference tokens by default, split UseReferenceTokens into two settings and allow the Data Protection to fall back to JWT for specific token types

pull/996/head
Kévin Chalet 6 years ago
committed by GitHub
parent
commit
beb6b3e92b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 34
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionBuilder.cs
  2. 6
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionExtensions.cs
  3. 97
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlerFilters.cs
  4. 16
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs
  5. 30
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionOptions.cs
  6. 21
      src/OpenIddict.Server/OpenIddictServerBuilder.cs
  7. 4
      src/OpenIddict.Server/OpenIddictServerConfiguration.cs
  8. 5
      src/OpenIddict.Server/OpenIddictServerExtensions.cs
  9. 30
      src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs
  10. 12
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  11. 21
      src/OpenIddict.Server/OpenIddictServerOptions.cs
  12. 4
      src/OpenIddict.Validation.ServerIntegration/OpenIddictValidationServerIntegrationConfiguration.cs
  13. 9
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Introspection.cs
  14. 18
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs
  15. 124
      test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs

34
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionBuilder.cs

@ -81,11 +81,39 @@ namespace Microsoft.Extensions.DependencyInjection
} }
/// <summary> /// <summary>
/// Configures OpenIddict to use the default token format (JWT) when issuing new tokens. /// Configures OpenIddict to use the default token format (JWT) when issuing new access tokens.
/// </summary> /// </summary>
/// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns> /// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns>
public OpenIddictServerDataProtectionBuilder PreferDefaultTokenFormat() public OpenIddictServerDataProtectionBuilder PreferDefaultAccessTokenFormat()
=> Configure(options => options.PreferDefaultTokenFormat = true); => Configure(options => options.PreferDefaultAccessTokenFormat = true);
/// <summary>
/// Configures OpenIddict to use the default token format (JWT) when issuing new authorization codes.
/// </summary>
/// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns>
public OpenIddictServerDataProtectionBuilder PreferDefaultAuthorizationCodeFormat()
=> Configure(options => options.PreferDefaultAuthorizationCodeFormat = true);
/// <summary>
/// Configures OpenIddict to use the default token format (JWT) when issuing new device codes.
/// </summary>
/// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns>
public OpenIddictServerDataProtectionBuilder PreferDefaultDeviceCodeFormat()
=> Configure(options => options.PreferDefaultDeviceCodeFormat = true);
/// <summary>
/// Configures OpenIddict to use the default token format (JWT) when issuing new refresh tokens.
/// </summary>
/// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns>
public OpenIddictServerDataProtectionBuilder PreferDefaultRefreshTokenFormat()
=> Configure(options => options.PreferDefaultRefreshTokenFormat = true);
/// <summary>
/// Configures OpenIddict to use the default token format (JWT) when issuing new user codes.
/// </summary>
/// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns>
public OpenIddictServerDataProtectionBuilder PreferDefaultUserCodeFormat()
=> Configure(options => options.PreferDefaultUserCodeFormat = true);
/// <summary> /// <summary>
/// Determines whether the specified object is equal to the current object. /// Determines whether the specified object is equal to the current object.

6
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionExtensions.cs

@ -42,7 +42,11 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Services.TryAdd(DefaultHandlers.Select(descriptor => descriptor.ServiceDescriptor)); builder.Services.TryAdd(DefaultHandlers.Select(descriptor => descriptor.ServiceDescriptor));
// Register the built-in filter used by the default OpenIddict Data Protection event handlers. // Register the built-in filter used by the default OpenIddict Data Protection event handlers.
builder.Services.TryAddSingleton<RequireDataProtectionFormatEnabled>(); builder.Services.TryAddSingleton<RequireDataProtectionAccessTokenFormatEnabled>();
builder.Services.TryAddSingleton<RequireDataProtectionAuthorizationCodeFormatEnabled>();
builder.Services.TryAddSingleton<RequireDataProtectionDeviceCodeFormatEnabled>();
builder.Services.TryAddSingleton<RequireDataProtectionRefreshTokenFormatEnabled>();
builder.Services.TryAddSingleton<RequireDataProtectionUserCodeFormatEnabled>();
// Note: TryAddEnumerable() is used here to ensure the initializers are registered only once. // Note: TryAddEnumerable() is used here to ensure the initializers are registered only once.
builder.Services.TryAddEnumerable(new[] builder.Services.TryAddEnumerable(new[]

97
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlerFilters.cs

@ -20,13 +20,14 @@ namespace OpenIddict.Server.DataProtection
public static class OpenIddictServerDataProtectionHandlerFilters public static class OpenIddictServerDataProtectionHandlerFilters
{ {
/// <summary> /// <summary>
/// Represents a filter that excludes the associated handlers if OpenIddict was not configured to issue Data Protection tokens. /// Represents a filter that excludes the associated handlers if OpenIddict
/// was not configured to issue ASP.NET Core Data Protection access tokens.
/// </summary> /// </summary>
public class RequireDataProtectionFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext> public class RequireDataProtectionAccessTokenFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{ {
private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options; private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options;
public RequireDataProtectionFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options) public RequireDataProtectionAccessTokenFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
=> _options = options; => _options = options;
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context) public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
@ -36,7 +37,95 @@ namespace OpenIddict.Server.DataProtection
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultTokenFormat); return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultAccessTokenFormat);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if OpenIddict
/// was not configured to issue ASP.NET Core Data Protection authorization codes.
/// </summary>
public class RequireDataProtectionAuthorizationCodeFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options;
public RequireDataProtectionAuthorizationCodeFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
=> _options = options;
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultAuthorizationCodeFormat);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if OpenIddict
/// was not configured to issue ASP.NET Core Data Protection device codes.
/// </summary>
public class RequireDataProtectionDeviceCodeFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options;
public RequireDataProtectionDeviceCodeFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
=> _options = options;
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultDeviceCodeFormat);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if OpenIddict
/// was not configured to issue ASP.NET Core Data Protection refresh tokens.
/// </summary>
public class RequireDataProtectionRefreshTokenFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options;
public RequireDataProtectionRefreshTokenFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
=> _options = options;
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultRefreshTokenFormat);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if OpenIddict
/// was not configured to issue ASP.NET Core Data Protection user codes.
/// </summary>
public class RequireDataProtectionUserCodeFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options;
public RequireDataProtectionUserCodeFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
=> _options = options;
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultUserCodeFormat);
} }
} }
} }

16
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs

@ -178,7 +178,7 @@ namespace OpenIddict.Server.DataProtection
public static OpenIddictServerHandlerDescriptor Descriptor { get; } public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireAccessTokenIncluded>() .AddFilter<RequireAccessTokenIncluded>()
.AddFilter<RequireDataProtectionFormatEnabled>() .AddFilter<RequireDataProtectionAccessTokenFormatEnabled>()
.UseSingletonHandler<GenerateDataProtectionAccessToken>() .UseSingletonHandler<GenerateDataProtectionAccessToken>()
.SetOrder(GenerateIdentityModelAccessToken.Descriptor.Order - 500) .SetOrder(GenerateIdentityModelAccessToken.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn) .SetType(OpenIddictServerHandlerType.BuiltIn)
@ -205,7 +205,7 @@ namespace OpenIddict.Server.DataProtection
} }
// Create a Data Protection protector using the provider registered in the options. // Create a Data Protection protector using the provider registered in the options.
var protector = context.Options.UseReferenceTokens ? var protector = context.Options.UseReferenceAccessTokens ?
_options.CurrentValue.DataProtectionProvider.CreateProtector( _options.CurrentValue.DataProtectionProvider.CreateProtector(
Handlers.Server, Formats.AccessToken, Features.ReferenceTokens, Schemes.Server) : Handlers.Server, Formats.AccessToken, Features.ReferenceTokens, Schemes.Server) :
_options.CurrentValue.DataProtectionProvider.CreateProtector( _options.CurrentValue.DataProtectionProvider.CreateProtector(
@ -243,7 +243,7 @@ namespace OpenIddict.Server.DataProtection
public static OpenIddictServerHandlerDescriptor Descriptor { get; } public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireAuthorizationCodeIncluded>() .AddFilter<RequireAuthorizationCodeIncluded>()
.AddFilter<RequireDataProtectionFormatEnabled>() .AddFilter<RequireDataProtectionAuthorizationCodeFormatEnabled>()
.UseSingletonHandler<GenerateDataProtectionAuthorizationCode>() .UseSingletonHandler<GenerateDataProtectionAuthorizationCode>()
.SetOrder(GenerateIdentityModelAuthorizationCode.Descriptor.Order - 500) .SetOrder(GenerateIdentityModelAuthorizationCode.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn) .SetType(OpenIddictServerHandlerType.BuiltIn)
@ -270,7 +270,7 @@ namespace OpenIddict.Server.DataProtection
} }
// Create a Data Protection protector using the provider registered in the options. // Create a Data Protection protector using the provider registered in the options.
var protector = context.Options.UseReferenceTokens ? var protector = !context.Options.DisableTokenStorage ?
_options.CurrentValue.DataProtectionProvider.CreateProtector( _options.CurrentValue.DataProtectionProvider.CreateProtector(
Handlers.Server, Formats.AuthorizationCode, Features.ReferenceTokens, Schemes.Server) : Handlers.Server, Formats.AuthorizationCode, Features.ReferenceTokens, Schemes.Server) :
_options.CurrentValue.DataProtectionProvider.CreateProtector( _options.CurrentValue.DataProtectionProvider.CreateProtector(
@ -308,7 +308,7 @@ namespace OpenIddict.Server.DataProtection
public static OpenIddictServerHandlerDescriptor Descriptor { get; } public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireDeviceCodeIncluded>() .AddFilter<RequireDeviceCodeIncluded>()
.AddFilter<RequireDataProtectionFormatEnabled>() .AddFilter<RequireDataProtectionDeviceCodeFormatEnabled>()
.UseSingletonHandler<GenerateDataProtectionDeviceCode>() .UseSingletonHandler<GenerateDataProtectionDeviceCode>()
.SetOrder(GenerateIdentityModelDeviceCode.Descriptor.Order - 500) .SetOrder(GenerateIdentityModelDeviceCode.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn) .SetType(OpenIddictServerHandlerType.BuiltIn)
@ -373,7 +373,7 @@ namespace OpenIddict.Server.DataProtection
public static OpenIddictServerHandlerDescriptor Descriptor { get; } public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireRefreshTokenIncluded>() .AddFilter<RequireRefreshTokenIncluded>()
.AddFilter<RequireDataProtectionFormatEnabled>() .AddFilter<RequireDataProtectionRefreshTokenFormatEnabled>()
.UseSingletonHandler<GenerateDataProtectionRefreshToken>() .UseSingletonHandler<GenerateDataProtectionRefreshToken>()
.SetOrder(GenerateIdentityModelRefreshToken.Descriptor.Order - 500) .SetOrder(GenerateIdentityModelRefreshToken.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn) .SetType(OpenIddictServerHandlerType.BuiltIn)
@ -400,7 +400,7 @@ namespace OpenIddict.Server.DataProtection
} }
// Create a Data Protection protector using the provider registered in the options. // Create a Data Protection protector using the provider registered in the options.
var protector = context.Options.UseReferenceTokens ? var protector = context.Options.UseReferenceRefreshTokens ?
_options.CurrentValue.DataProtectionProvider.CreateProtector( _options.CurrentValue.DataProtectionProvider.CreateProtector(
Handlers.Server, Formats.RefreshToken, Features.ReferenceTokens, Schemes.Server) : Handlers.Server, Formats.RefreshToken, Features.ReferenceTokens, Schemes.Server) :
_options.CurrentValue.DataProtectionProvider.CreateProtector( _options.CurrentValue.DataProtectionProvider.CreateProtector(
@ -438,7 +438,7 @@ namespace OpenIddict.Server.DataProtection
public static OpenIddictServerHandlerDescriptor Descriptor { get; } public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireUserCodeIncluded>() .AddFilter<RequireUserCodeIncluded>()
.AddFilter<RequireDataProtectionFormatEnabled>() .AddFilter<RequireDataProtectionUserCodeFormatEnabled>()
.UseSingletonHandler<GenerateDataProtectionUserCode>() .UseSingletonHandler<GenerateDataProtectionUserCode>()
.SetOrder(GenerateIdentityModelUserCode.Descriptor.Order - 500) .SetOrder(GenerateIdentityModelUserCode.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn) .SetType(OpenIddictServerHandlerType.BuiltIn)

30
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionOptions.cs

@ -29,9 +29,33 @@ namespace OpenIddict.Server.DataProtection
= new OpenIddictServerDataProtectionFormatter(); = new OpenIddictServerDataProtectionFormatter();
/// <summary> /// <summary>
/// Gets or sets a boolean indicating whether the default token format should be /// Gets or sets a boolean indicating whether the default access token format should be
/// used when issuing new tokens. This property is set to <c>false</c> by default. /// used when issuing new access tokens. This property is set to <c>false</c> by default.
/// </summary> /// </summary>
public bool PreferDefaultTokenFormat { get; set; } public bool PreferDefaultAccessTokenFormat { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the default authorization code format should be
/// used when issuing new authorization codes. This property is set to <c>false</c> by default.
/// </summary>
public bool PreferDefaultAuthorizationCodeFormat { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the default device code format should be
/// used when issuing new device codes. This property is set to <c>false</c> by default.
/// </summary>
public bool PreferDefaultDeviceCodeFormat { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the default refresh token format should be
/// used when issuing new refresh tokens. This property is set to <c>false</c> by default.
/// </summary>
public bool PreferDefaultRefreshTokenFormat { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the default user code format should be
/// used when issuing new user codes. This property is set to <c>false</c> by default.
/// </summary>
public bool PreferDefaultUserCodeFormat { get; set; }
} }
} }

21
src/OpenIddict.Server/OpenIddictServerBuilder.cs

@ -1782,15 +1782,26 @@ namespace Microsoft.Extensions.DependencyInjection
} }
/// <summary> /// <summary>
/// Configures OpenIddict to use reference tokens, so that the token and code payloads /// Configures OpenIddict to use reference tokens, so that the access token payloads
/// are stored in the database (only an identifier is returned to the client application). /// are stored in the database (only an identifier is returned to the client application).
/// Enabling this option is useful when storing a very large number of claims in the tokens, /// Enabling this option is useful when storing a very large number of claims in the tokens,
/// but it is RECOMMENDED to enable column encryption in the database or use the ASP.NET Core /// but it is RECOMMENDED to enable column encryption in the database or use the ASP.NET Core
/// Data Protection integration, that provides additional protection against token leakage. /// Data Protection integration, that provides additional protection against token leakage.
/// </summary> /// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns> /// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder UseReferenceTokens() public OpenIddictServerBuilder UseReferenceAccessTokens()
=> Configure(options => options.UseReferenceTokens = true); => Configure(options => options.UseReferenceAccessTokens = true);
/// <summary>
/// Configures OpenIddict to use reference tokens, so that the refresh token payloads
/// are stored in the database (only an identifier is returned to the client application).
/// Enabling this option is useful when storing a very large number of claims in the tokens,
/// but it is RECOMMENDED to enable column encryption in the database or use the ASP.NET Core
/// Data Protection integration, that provides additional protection against token leakage.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder UseReferenceRefreshTokens()
=> Configure(options => options.UseReferenceRefreshTokens = true);
/// <summary> /// <summary>
/// Configures OpenIddict to use rolling refresh tokens. When this option is enabled, /// Configures OpenIddict to use rolling refresh tokens. When this option is enabled,
@ -1798,8 +1809,8 @@ namespace Microsoft.Extensions.DependencyInjection
/// one is automatically revoked unless token storage was explicitly disabled). /// one is automatically revoked unless token storage was explicitly disabled).
/// </summary> /// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns> /// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder UseRollingTokens() public OpenIddictServerBuilder UseRollingRefreshTokens()
=> Configure(options => options.UseRollingTokens = true); => Configure(options => options.UseRollingRefreshTokens = true);
/// <summary> /// <summary>
/// Determines whether the specified object is equal to the current object. /// Determines whether the specified object is equal to the current object.

4
src/OpenIddict.Server/OpenIddictServerConfiguration.cs

@ -96,12 +96,12 @@ namespace OpenIddict.Server
throw new InvalidOperationException("The revocation endpoint cannot be enabled when token storage is disabled."); throw new InvalidOperationException("The revocation endpoint cannot be enabled when token storage is disabled.");
} }
if (options.UseReferenceTokens) if (options.UseReferenceAccessTokens || options.UseReferenceRefreshTokens)
{ {
throw new InvalidOperationException("Reference tokens cannot be used when disabling token storage."); throw new InvalidOperationException("Reference tokens cannot be used when disabling token storage.");
} }
if (options.UseSlidingExpiration && !options.UseRollingTokens) if (options.UseSlidingExpiration && !options.UseRollingRefreshTokens)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(new StringBuilder()
.Append("Sliding expiration must be disabled when turning off token storage if rolling tokens are not used.") .Append("Sliding expiration must be disabled when turning off token storage if rolling tokens are not used.")

5
src/OpenIddict.Server/OpenIddictServerExtensions.cs

@ -54,10 +54,11 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Services.TryAddSingleton<RequireGrantTypePermissionsEnabled>(); builder.Services.TryAddSingleton<RequireGrantTypePermissionsEnabled>();
builder.Services.TryAddSingleton<RequireIdentityTokenIncluded>(); builder.Services.TryAddSingleton<RequireIdentityTokenIncluded>();
builder.Services.TryAddSingleton<RequirePostLogoutRedirectUriParameter>(); builder.Services.TryAddSingleton<RequirePostLogoutRedirectUriParameter>();
builder.Services.TryAddSingleton<RequireReferenceTokensEnabled>(); builder.Services.TryAddSingleton<RequireReferenceAccessTokensEnabled>();
builder.Services.TryAddSingleton<RequireReferenceRefreshTokensEnabled>();
builder.Services.TryAddSingleton<RequireRefreshTokenIncluded>(); builder.Services.TryAddSingleton<RequireRefreshTokenIncluded>();
builder.Services.TryAddSingleton<RequireRollingTokensDisabled>(); builder.Services.TryAddSingleton<RequireRollingTokensDisabled>();
builder.Services.TryAddSingleton<RequireRollingTokensEnabled>(); builder.Services.TryAddSingleton<RequireRollingRefreshTokensEnabled>();
builder.Services.TryAddSingleton<RequireSlidingExpirationEnabled>(); builder.Services.TryAddSingleton<RequireSlidingExpirationEnabled>();
builder.Services.TryAddSingleton<RequireScopePermissionsEnabled>(); builder.Services.TryAddSingleton<RequireScopePermissionsEnabled>();
builder.Services.TryAddSingleton<RequireScopeValidationEnabled>(); builder.Services.TryAddSingleton<RequireScopeValidationEnabled>();

30
src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs

@ -176,9 +176,9 @@ namespace OpenIddict.Server
} }
/// <summary> /// <summary>
/// Represents a filter that excludes the associated handlers if reference tokens are disabled. /// Represents a filter that excludes the associated handlers if reference access tokens are disabled.
/// </summary> /// </summary>
public class RequireReferenceTokensEnabled : IOpenIddictServerHandlerFilter<BaseContext> public class RequireReferenceAccessTokensEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{ {
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context) public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{ {
@ -187,7 +187,23 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
return new ValueTask<bool>(context.Options.UseReferenceTokens); return new ValueTask<bool>(context.Options.UseReferenceAccessTokens);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if reference refresh tokens are disabled.
/// </summary>
public class RequireReferenceRefreshTokensEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(context.Options.UseReferenceRefreshTokens);
} }
} }
@ -219,14 +235,14 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
return new ValueTask<bool>(!context.Options.UseRollingTokens); return new ValueTask<bool>(!context.Options.UseRollingRefreshTokens);
} }
} }
/// <summary> /// <summary>
/// Represents a filter that excludes the associated handlers if rolling tokens were not enabled. /// Represents a filter that excludes the associated handlers if rolling refresh tokens were not enabled.
/// </summary> /// </summary>
public class RequireRollingTokensEnabled : IOpenIddictServerHandlerFilter<BaseContext> public class RequireRollingRefreshTokensEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{ {
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context) public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{ {
@ -235,7 +251,7 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
return new ValueTask<bool>(context.Options.UseRollingTokens); return new ValueTask<bool>(context.Options.UseRollingRefreshTokens);
} }
} }

12
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -1764,7 +1764,8 @@ namespace OpenIddict.Server
OpenIddictServerEndpointType.Token when !context.Principal.HasScope(Scopes.OfflineAccess) => false, OpenIddictServerEndpointType.Token when !context.Principal.HasScope(Scopes.OfflineAccess) => false,
// For grant_type=refresh_token token requests, only return a refresh token if rolling tokens are enabled. // For grant_type=refresh_token token requests, only return a refresh token if rolling tokens are enabled.
OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType() => context.Options.UseRollingTokens, OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType()
=> context.Options.UseRollingRefreshTokens,
// For token requests that don't meet the previous criteria, allow a refresh token to be returned. // For token requests that don't meet the previous criteria, allow a refresh token to be returned.
OpenIddictServerEndpointType.Token => true, OpenIddictServerEndpointType.Token => true,
@ -2547,7 +2548,7 @@ namespace OpenIddict.Server
return; return;
} }
if (context.Request.IsRefreshTokenGrantType() && !context.Options.UseRollingTokens) if (context.Request.IsRefreshTokenGrantType() && !context.Options.UseRollingRefreshTokens)
{ {
return; return;
} }
@ -2615,7 +2616,7 @@ namespace OpenIddict.Server
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireDegradedModeDisabled>() .AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequireTokenStorageEnabled>() .AddFilter<RequireTokenStorageEnabled>()
.AddFilter<RequireRollingTokensEnabled>() .AddFilter<RequireRollingRefreshTokensEnabled>()
.UseScopedHandler<RevokeExistingTokenEntries>() .UseScopedHandler<RevokeExistingTokenEntries>()
.SetOrder(RedeemTokenEntry.Descriptor.Order + 1_000) .SetOrder(RedeemTokenEntry.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn) .SetType(OpenIddictServerHandlerType.BuiltIn)
@ -2980,7 +2981,7 @@ namespace OpenIddict.Server
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireDegradedModeDisabled>() .AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequireTokenStorageEnabled>() .AddFilter<RequireTokenStorageEnabled>()
.AddFilter<RequireReferenceTokensEnabled>() .AddFilter<RequireReferenceAccessTokensEnabled>()
.AddFilter<RequireAccessTokenIncluded>() .AddFilter<RequireAccessTokenIncluded>()
.UseScopedHandler<ConvertReferenceAccessToken>() .UseScopedHandler<ConvertReferenceAccessToken>()
.SetOrder(GenerateIdentityModelAccessToken.Descriptor.Order + 1_000) .SetOrder(GenerateIdentityModelAccessToken.Descriptor.Order + 1_000)
@ -3266,7 +3267,6 @@ namespace OpenIddict.Server
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireDegradedModeDisabled>() .AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequireTokenStorageEnabled>() .AddFilter<RequireTokenStorageEnabled>()
.AddFilter<RequireReferenceTokensEnabled>()
.AddFilter<RequireAuthorizationCodeIncluded>() .AddFilter<RequireAuthorizationCodeIncluded>()
.UseScopedHandler<ConvertReferenceAuthorizationCode>() .UseScopedHandler<ConvertReferenceAuthorizationCode>()
.SetOrder(GenerateIdentityModelAuthorizationCode.Descriptor.Order + 1_000) .SetOrder(GenerateIdentityModelAuthorizationCode.Descriptor.Order + 1_000)
@ -3945,7 +3945,7 @@ namespace OpenIddict.Server
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>() = OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireDegradedModeDisabled>() .AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequireTokenStorageEnabled>() .AddFilter<RequireTokenStorageEnabled>()
.AddFilter<RequireReferenceTokensEnabled>() .AddFilter<RequireReferenceRefreshTokensEnabled>()
.AddFilter<RequireRefreshTokenIncluded>() .AddFilter<RequireRefreshTokenIncluded>()
.UseScopedHandler<ConvertReferenceRefreshToken>() .UseScopedHandler<ConvertReferenceRefreshToken>()
.SetOrder(GenerateIdentityModelRefreshToken.Descriptor.Order + 1_000) .SetOrder(GenerateIdentityModelRefreshToken.Descriptor.Order + 1_000)

21
src/OpenIddict.Server/OpenIddictServerOptions.cs

@ -334,15 +334,26 @@ namespace OpenIddict.Server
}; };
/// <summary> /// <summary>
/// Gets or sets a boolean indicating whether reference tokens should be used. /// Gets or sets a boolean indicating whether reference access tokens should be used.
/// When set to <c>true</c>, token and code payloads are stored in the database /// When set to <c>true</c>, the token payload is stored in the database and a
/// and a crypto-secure random identifier is returned to the client application. /// crypto-secure random identifier is returned to the client application.
/// Enabling this option is useful when storing a very large number of claims /// Enabling this option is useful when storing a very large number of claims
/// in the tokens, but it is RECOMMENDED to enable column encryption /// in the tokens, but it is RECOMMENDED to enable column encryption
/// in the database or use the ASP.NET Core Data Protection integration, /// in the database or use the ASP.NET Core Data Protection integration,
/// that provides additional protection against token leakage. /// that provides additional protection against token leakage.
/// </summary> /// </summary>
public bool UseReferenceTokens { get; set; } public bool UseReferenceAccessTokens { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether reference refresh tokens should be used.
/// When set to <c>true</c>, the token payload is stored in the database and a
/// crypto-secure random identifier is returned to the client application.
/// Enabling this option is useful when storing a very large number of claims
/// in the tokens, but it is RECOMMENDED to enable column encryption
/// in the database or use the ASP.NET Core Data Protection integration,
/// that provides additional protection against token leakage.
/// </summary>
public bool UseReferenceRefreshTokens { get; set; }
/// <summary> /// <summary>
/// Gets or sets a boolean indicating whether rolling tokens should be used. /// Gets or sets a boolean indicating whether rolling tokens should be used.
@ -352,6 +363,6 @@ namespace OpenIddict.Server
/// refresh token request (and the previous one is automatically revoked /// refresh token request (and the previous one is automatically revoked
/// unless token storage was explicitly disabled in the options). /// unless token storage was explicitly disabled in the options).
/// </summary> /// </summary>
public bool UseRollingTokens { get; set; } public bool UseRollingRefreshTokens { get; set; }
} }
} }

4
src/OpenIddict.Validation.ServerIntegration/OpenIddictValidationServerIntegrationConfiguration.cs

@ -59,8 +59,8 @@ namespace OpenIddict.Validation.ServerIntegration
options.EncryptionCredentials.Add(credentials); options.EncryptionCredentials.Add(credentials);
} }
// Note: token entry validation must be enabled to be able to validate reference tokens. // Note: token entry validation must be enabled to be able to validate reference access tokens.
options.EnableTokenEntryValidation = _options.CurrentValue.UseReferenceTokens; options.EnableTokenEntryValidation = _options.CurrentValue.UseReferenceAccessTokens;
} }
/// <summary> /// <summary>

9
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Introspection.cs

@ -1217,8 +1217,6 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options => await using var server = await CreateServerAsync(options =>
{ {
options.UseReferenceTokens();
options.Services.AddSingleton(CreateApplicationManager(mock => options.Services.AddSingleton(CreateApplicationManager(mock =>
{ {
var application = new OpenIddictApplication(); var application = new OpenIddictApplication();
@ -1329,7 +1327,6 @@ namespace OpenIddict.Server.FunctionalTests
options.Services.AddSingleton(manager); options.Services.AddSingleton(manager);
options.DisableAuthorizationStorage(); options.DisableAuthorizationStorage();
options.UseReferenceTokens();
}); });
await using var client = await server.CreateClientAsync(); await using var client = await server.CreateClientAsync();
@ -1421,8 +1418,6 @@ namespace OpenIddict.Server.FunctionalTests
options.Services.AddSingleton(manager); options.Services.AddSingleton(manager);
options.UseReferenceTokens();
options.RemoveEventHandler(NormalizeErrorResponse.Descriptor); options.RemoveEventHandler(NormalizeErrorResponse.Descriptor);
}); });
@ -1521,8 +1516,6 @@ namespace OpenIddict.Server.FunctionalTests
options.Services.AddSingleton(manager); options.Services.AddSingleton(manager);
options.UseReferenceTokens();
options.RemoveEventHandler(NormalizeErrorResponse.Descriptor); options.RemoveEventHandler(NormalizeErrorResponse.Descriptor);
}); });
@ -1608,8 +1601,6 @@ namespace OpenIddict.Server.FunctionalTests
options.Services.AddSingleton(manager); options.Services.AddSingleton(manager);
options.UseReferenceTokens();
options.RemoveEventHandler(NormalizeErrorResponse.Descriptor); options.RemoveEventHandler(NormalizeErrorResponse.Descriptor);
}); });

18
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs

@ -2888,7 +2888,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options => await using var server = await CreateServerAsync(options =>
{ {
options.EnableDegradedMode(); options.EnableDegradedMode();
options.UseRollingTokens(); options.UseRollingRefreshTokens();
options.AddEventHandler<ProcessAuthenticationContext>(builder => options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{ {
@ -2940,7 +2940,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options => await using var server = await CreateServerAsync(options =>
{ {
options.EnableDegradedMode(); options.EnableDegradedMode();
options.UseRollingTokens(); options.UseRollingRefreshTokens();
options.AddEventHandler<ProcessAuthenticationContext>(builder => options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{ {
@ -2984,7 +2984,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options => await using var server = await CreateServerAsync(options =>
{ {
options.EnableDegradedMode(); options.EnableDegradedMode();
options.UseRollingTokens(); options.UseRollingRefreshTokens();
options.AddEventHandler<ProcessAuthenticationContext>(builder => options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{ {
@ -3240,7 +3240,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options => await using var server = await CreateServerAsync(options =>
{ {
options.UseRollingTokens(); options.UseRollingRefreshTokens();
options.DisableAuthorizationStorage(); options.DisableAuthorizationStorage();
options.AddEventHandler<ProcessAuthenticationContext>(builder => options.AddEventHandler<ProcessAuthenticationContext>(builder =>
@ -3307,7 +3307,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options => await using var server = await CreateServerAsync(options =>
{ {
options.UseRollingTokens(); options.UseRollingRefreshTokens();
options.DisableAuthorizationStorage(); options.DisableAuthorizationStorage();
options.AddEventHandler<ProcessAuthenticationContext>(builder => options.AddEventHandler<ProcessAuthenticationContext>(builder =>
@ -3456,7 +3456,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options => await using var server = await CreateServerAsync(options =>
{ {
options.UseRollingTokens(); options.UseRollingRefreshTokens();
options.AddEventHandler<ProcessAuthenticationContext>(builder => options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{ {
@ -3969,6 +3969,9 @@ namespace OpenIddict.Server.FunctionalTests
mock.Setup(manager => manager.GetIdAsync(token, It.IsAny<CancellationToken>())) mock.Setup(manager => manager.GetIdAsync(token, It.IsAny<CancellationToken>()))
.ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56"); .ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56");
mock.Setup(manager => manager.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
})); }));
options.Services.AddSingleton(manager); options.Services.AddSingleton(manager);
@ -4042,6 +4045,9 @@ namespace OpenIddict.Server.FunctionalTests
mock.Setup(manager => manager.GetIdAsync(token, It.IsAny<CancellationToken>())) mock.Setup(manager => manager.GetIdAsync(token, It.IsAny<CancellationToken>()))
.ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56"); .ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56");
mock.Setup(manager => manager.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
})); }));
options.Services.AddSingleton(manager); options.Services.AddSingleton(manager);

124
test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs

@ -35,7 +35,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Action<OpenIddictServerHandlerDescriptor.Builder<CustomContext>> configuration = null; Action<OpenIddictServerHandlerDescriptor.Builder<CustomContext>> configuration = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEventHandler(configuration)); var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEventHandler(configuration));
Assert.Equal(nameof(configuration), exception.ParamName); Assert.Equal(nameof(configuration), exception.ParamName);
} }
@ -48,7 +48,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
OpenIddictServerHandlerDescriptor descriptor = null; OpenIddictServerHandlerDescriptor descriptor = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEventHandler(descriptor)); var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEventHandler(descriptor));
Assert.Equal(nameof(descriptor), exception.ParamName); Assert.Equal(nameof(descriptor), exception.ParamName);
} }
@ -136,7 +136,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
EncryptingCredentials credentials = null; EncryptingCredentials credentials = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEncryptionCredentials(credentials)); var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEncryptionCredentials(credentials));
Assert.Equal(nameof(credentials), exception.ParamName); Assert.Equal(nameof(credentials), exception.ParamName);
} }
@ -149,7 +149,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
SecurityKey key = null; SecurityKey key = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEncryptionKey(key)); var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEncryptionKey(key));
Assert.Equal(nameof(key), exception.ParamName); Assert.Equal(nameof(key), exception.ParamName);
} }
@ -163,7 +163,7 @@ namespace OpenIddict.Server.Tests
var key = new Mock<AsymmetricSecurityKey>(); var key = new Mock<AsymmetricSecurityKey>();
key.SetupGet(x => x.PrivateKeyStatus).Returns(PrivateKeyStatus.DoesNotExist); key.SetupGet(x => x.PrivateKeyStatus).Returns(PrivateKeyStatus.DoesNotExist);
// Act & Assert // Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.AddEncryptionKey(key.Object)); var exception = Assert.Throws<InvalidOperationException>(() => builder.AddEncryptionKey(key.Object));
Assert.Equal("The asymmetric encryption key doesn't contain the required private key.", exception.Message); Assert.Equal("The asymmetric encryption key doesn't contain the required private key.", exception.Message);
} }
@ -194,7 +194,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
OpenIddictServerHandlerDescriptor descriptor = null; OpenIddictServerHandlerDescriptor descriptor = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.RemoveEventHandler(descriptor)); var exception = Assert.Throws<ArgumentNullException>(() => builder.RemoveEventHandler(descriptor));
Assert.Equal(nameof(descriptor), exception.ParamName); Assert.Equal(nameof(descriptor), exception.ParamName);
} }
@ -242,7 +242,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Action<OpenIddictServerOptions> configuration = null; Action<OpenIddictServerOptions> configuration = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.Configure(configuration)); var exception = Assert.Throws<ArgumentNullException>(() => builder.Configure(configuration));
Assert.Equal(nameof(configuration), exception.ParamName); Assert.Equal(nameof(configuration), exception.ParamName);
} }
@ -271,7 +271,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
X500DistinguishedName subject = null; X500DistinguishedName subject = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.AddDevelopmentEncryptionCertificate(subject)); var exception = Assert.Throws<ArgumentNullException>(() => builder.AddDevelopmentEncryptionCertificate(subject));
Assert.Equal(nameof(subject), exception.ParamName); Assert.Equal(nameof(subject), exception.ParamName);
} }
@ -455,7 +455,7 @@ namespace OpenIddict.Server.Tests
var services = CreateServices(); var services = CreateServices();
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.AllowCustomFlow(type)); var exception = Assert.Throws<ArgumentException>(() => builder.AllowCustomFlow(type));
Assert.Equal(nameof(type), exception.ParamName); Assert.Equal(nameof(type), exception.ParamName);
Assert.Contains("The grant type cannot be null or empty.", exception.Message); Assert.Contains("The grant type cannot be null or empty.", exception.Message);
@ -533,7 +533,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = null; Uri[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetConfigurationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetConfigurationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -546,7 +546,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] addresses = null; string[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetConfigurationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetConfigurationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -562,7 +562,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), }; Uri[] addresses = { new Uri(uri), };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetConfigurationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentException>(() => builder.SetConfigurationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message); Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -608,7 +608,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = null; Uri[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetDeviceEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetDeviceEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -621,7 +621,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] addresses = null; string[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetDeviceEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetDeviceEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -635,7 +635,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), }; Uri[] addresses = { new Uri(uri), };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetDeviceEndpointUris(addresses)); var exception = Assert.Throws<ArgumentException>(() => builder.SetDeviceEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message); Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -697,7 +697,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = null; Uri[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetCryptographyEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetCryptographyEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -710,7 +710,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] addresses = null; string[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetCryptographyEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetCryptographyEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -724,7 +724,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), }; Uri[] addresses = { new Uri(uri), };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetCryptographyEndpointUris(addresses)); var exception = Assert.Throws<ArgumentException>(() => builder.SetCryptographyEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message); Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -818,7 +818,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = null; Uri[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetAuthorizationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetAuthorizationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -831,7 +831,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] addresses = null; string[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetAuthorizationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetAuthorizationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -845,7 +845,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), }; Uri[] addresses = { new Uri(uri), };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetAuthorizationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentException>(() => builder.SetAuthorizationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message); Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -891,7 +891,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = null; Uri[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetIntrospectionEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetIntrospectionEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -904,7 +904,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] addresses = null; string[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetIntrospectionEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetIntrospectionEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -918,7 +918,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), }; Uri[] addresses = { new Uri(uri), };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetIntrospectionEndpointUris(addresses)); var exception = Assert.Throws<ArgumentException>(() => builder.SetIntrospectionEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message); Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -964,7 +964,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = null; Uri[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetLogoutEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetLogoutEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -977,7 +977,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] addresses = null; string[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetLogoutEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetLogoutEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -991,7 +991,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), }; Uri[] addresses = { new Uri(uri), };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetLogoutEndpointUris(addresses)); var exception = Assert.Throws<ArgumentException>(() => builder.SetLogoutEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message); Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -1037,7 +1037,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = null; Uri[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetRevocationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetRevocationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -1050,7 +1050,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] addresses = null; string[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetRevocationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetRevocationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -1064,7 +1064,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), }; Uri[] addresses = { new Uri(uri), };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetRevocationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentException>(() => builder.SetRevocationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message); Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -1126,7 +1126,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = null; Uri[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetTokenEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetTokenEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -1139,7 +1139,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] addresses = null; string[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetTokenEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetTokenEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -1153,7 +1153,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), }; Uri[] addresses = { new Uri(uri), };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetTokenEndpointUris(addresses)); var exception = Assert.Throws<ArgumentException>(() => builder.SetTokenEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message); Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -1199,7 +1199,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = null; Uri[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetUserinfoEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetUserinfoEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -1212,7 +1212,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] addresses = null; string[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetUserinfoEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetUserinfoEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -1226,7 +1226,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = {new Uri(uri), }; Uri[] addresses = {new Uri(uri), };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetUserinfoEndpointUris(addresses)); var exception = Assert.Throws<ArgumentException>(() => builder.SetUserinfoEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message); Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -1526,7 +1526,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] claims = null; string[] claims = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.RegisterClaims(claims)); var exception = Assert.Throws<ArgumentNullException>(() => builder.RegisterClaims(claims));
Assert.Equal(nameof(claims), exception.ParamName); Assert.Equal(nameof(claims), exception.ParamName);
} }
@ -1541,7 +1541,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] claims = { claim }; string[] claims = { claim };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.RegisterClaims(claims)); var exception = Assert.Throws<ArgumentException>(() => builder.RegisterClaims(claims));
Assert.Equal(nameof(claims), exception.ParamName); Assert.Equal(nameof(claims), exception.ParamName);
Assert.Contains("Claims cannot be null or empty.", exception.Message); Assert.Contains("Claims cannot be null or empty.", exception.Message);
@ -1572,7 +1572,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] scopes = null; string[] scopes = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.RegisterScopes(scopes)); var exception = Assert.Throws<ArgumentNullException>(() => builder.RegisterScopes(scopes));
Assert.Equal(nameof(scopes), exception.ParamName); Assert.Equal(nameof(scopes), exception.ParamName);
} }
@ -1587,26 +1587,58 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] scopes = { scope }; string[] scopes = { scope };
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.RegisterScopes(scopes)); var exception = Assert.Throws<ArgumentException>(() => builder.RegisterScopes(scopes));
Assert.Equal(nameof(scopes), exception.ParamName); Assert.Equal(nameof(scopes), exception.ParamName);
Assert.Contains("Scopes cannot be null or empty.", exception.Message); Assert.Contains("Scopes cannot be null or empty.", exception.Message);
} }
[Fact] [Fact]
public void UseReferenceTokens_ReferenceTokensAreEnabled() public void UseReferenceAccessTokens_ReferenceAccessTokensAreEnabled()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.UseReferenceAccessTokens();
var options = GetOptions(services);
// Assert
Assert.True(options.UseReferenceAccessTokens);
}
[Fact]
public void UseReferenceRefreshTokens_ReferenceRefreshTokensAreEnabled()
{ {
// Arrange // Arrange
var services = CreateServices(); var services = CreateServices();
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
// Act // Act
builder.UseReferenceTokens(); builder.UseReferenceRefreshTokens();
var options = GetOptions(services); var options = GetOptions(services);
// Assert // Assert
Assert.True(options.UseReferenceTokens); Assert.True(options.UseReferenceRefreshTokens);
}
[Fact]
public void UseRollingRefreshTokens_RollingRefreshTokensAreEnabled()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.UseRollingRefreshTokens();
var options = GetOptions(services);
// Assert
Assert.True(options.UseRollingRefreshTokens);
} }
[Fact] [Fact]
@ -1617,7 +1649,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = null; Uri[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetVerificationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetVerificationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -1630,7 +1662,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
string[] addresses = null; string[] addresses = null;
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetVerificationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentNullException>(() => builder.SetVerificationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
} }
@ -1661,7 +1693,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services); var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri)}; Uri[] addresses = { new Uri(uri)};
// Act & Assert // Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetVerificationEndpointUris(addresses)); var exception = Assert.Throws<ArgumentException>(() => builder.SetVerificationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName); Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message); Assert.Contains("One of the specified addresses is not valid.", exception.Message);

Loading…
Cancel
Save