diff --git a/samples/Mvc.Server/Startup.cs b/samples/Mvc.Server/Startup.cs index c51e82f3..c7977242 100644 --- a/samples/Mvc.Server/Startup.cs +++ b/samples/Mvc.Server/Startup.cs @@ -101,9 +101,6 @@ namespace Mvc.Server OpenIdConnectConstants.Scopes.Profile, OpenIddictConstants.Scopes.Roles); - // Make the "client_id" parameter mandatory when sending a token request. - options.RequireClientIdentification(); - // When request caching is enabled, authorization and logout requests // are stored in the distributed cache by OpenIddict and the user agent // is redirected to the same page with a single parameter (request_id). @@ -111,10 +108,6 @@ namespace Mvc.Server // an external authentication provider like Google, Facebook or Twitter. options.EnableRequestCaching(); - // Enable scope validation, so that authorization and token requests - // that specify unregistered scopes are automatically rejected. - options.EnableScopeValidation(); - // During development, you can disable the HTTPS requirement. options.DisableHttpsRequirement(); @@ -123,6 +116,16 @@ namespace Mvc.Server // // options.UseJsonWebTokens(); // options.AddEphemeralSigningKey(); + + // Note: if you don't want to specify a client_id when sending + // a token or revocation request, uncomment the following line: + // + // options.AcceptAnonymousClients(); + + // Note: if you want to process authorization and token requests + // that specify non-registered scopes, uncomment the following line: + // + // options.DisableScopeValidation(); }) // Register the OpenIddict validation handler. diff --git a/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Authentication.cs b/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Authentication.cs index 2caaa150..a2e92059 100644 --- a/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Authentication.cs +++ b/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Authentication.cs @@ -180,7 +180,7 @@ namespace OpenIddict.Server } // Validates scopes, unless scope validation was explicitly disabled. - if (options.EnableScopeValidation) + if (!options.DisableScopeValidation) { var scopes = new HashSet(context.Request.GetScopes(), StringComparer.Ordinal); scopes.ExceptWith(options.Scopes); diff --git a/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Exchange.cs b/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Exchange.cs index c03d9703..458c3cb1 100644 --- a/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Exchange.cs +++ b/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Exchange.cs @@ -78,7 +78,7 @@ namespace OpenIddict.Server } // Validates scopes, unless scope validation was explicitly disabled. - if (options.EnableScopeValidation) + if (!options.DisableScopeValidation) { var scopes = new HashSet(context.Request.GetScopes(), StringComparer.Ordinal); scopes.ExceptWith(options.Scopes); @@ -127,7 +127,7 @@ namespace OpenIddict.Server if (string.IsNullOrEmpty(context.ClientId)) { // Reject the request if client identification is mandatory. - if (options.RequireClientIdentification) + if (!options.AcceptAnonymousClients) { _logger.LogError("The token request was rejected becaused the " + "mandatory client_id parameter was missing or empty."); diff --git a/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Revocation.cs b/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Revocation.cs index b6dbbfab..aceaacb9 100644 --- a/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Revocation.cs +++ b/src/OpenIddict.Server/Internal/OpenIddictServerProvider.Revocation.cs @@ -55,7 +55,7 @@ namespace OpenIddict.Server if (string.IsNullOrEmpty(context.ClientId)) { // Reject the request if client identification is mandatory. - if (options.RequireClientIdentification) + if (!options.AcceptAnonymousClients) { _logger.LogError("The revocation request was rejected becaused the " + "mandatory client_id parameter was missing or empty."); diff --git a/src/OpenIddict.Server/OpenIddictServerBuilder.cs b/src/OpenIddict.Server/OpenIddictServerBuilder.cs index fb7b4a93..c75dd76f 100644 --- a/src/OpenIddict.Server/OpenIddictServerBuilder.cs +++ b/src/OpenIddict.Server/OpenIddictServerBuilder.cs @@ -66,6 +66,14 @@ namespace Microsoft.Extensions.DependencyInjection return this; } + /// + /// Makes client identification optional so that token and revocation + /// requests that don't specify a client_id are not automatically rejected. + /// + /// The . + public OpenIddictServerBuilder AcceptAnonymousClients() + => Configure(options => options.AcceptAnonymousClients = true); + /// /// Registers (and generates if necessary) a user-specific development /// certificate used to sign the JWT tokens issued by OpenIddict. @@ -462,12 +470,12 @@ namespace Microsoft.Extensions.DependencyInjection } /// - /// Rejects authorization and token requests that specify scopes that have not been - /// registered using or the scope manager. + /// Allows processing authorization and token requests that specify scopes that have not + /// been registered using or the scope manager. /// /// The . - public OpenIddictServerBuilder EnableScopeValidation() - => Configure(options => options.EnableScopeValidation = true); + public OpenIddictServerBuilder DisableScopeValidation() + => Configure(options => options.DisableScopeValidation = true); /// /// Enables the token endpoint. @@ -595,16 +603,6 @@ namespace Microsoft.Extensions.DependencyInjection return Configure(options => options.Scopes.UnionWith(scopes)); } - /// - /// Makes client identification mandatory so that token and revocation - /// requests that don't specify a client_id are automatically rejected. - /// Note: enabling this option doesn't prevent public clients from using - /// the token and revocation endpoints, but specifying a client_id is required. - /// - /// The . - public OpenIddictServerBuilder RequireClientIdentification() - => Configure(options => options.RequireClientIdentification = true); - /// /// Sets the access token lifetime, after which client applications must retrieve /// a new access token by making a grant_type=refresh_token token request diff --git a/src/OpenIddict.Server/OpenIddictServerOptions.cs b/src/OpenIddict.Server/OpenIddictServerOptions.cs index d29c6c21..d9afb20a 100644 --- a/src/OpenIddict.Server/OpenIddictServerOptions.cs +++ b/src/OpenIddict.Server/OpenIddictServerOptions.cs @@ -27,6 +27,13 @@ namespace OpenIddict.Server ProviderType = typeof(OpenIddictServerProvider); } + /// + /// Gets or sets a boolean determining whether client identification is optional. + /// Enabling this option allows client applications to communicate with the token + /// and revocation endpoints without having to send their client identifier. + /// + public bool AcceptAnonymousClients { get; set; } + /// /// Gets or sets the user-provided that the OpenIddict server /// invokes to enable developer control over the entire authentication/authorization process. @@ -84,9 +91,9 @@ namespace OpenIddict.Server public bool EnableRequestCaching { get; set; } /// - /// Gets or sets a boolean indicating whether scope validation is enabled. + /// Gets or sets a boolean indicating whether scope validation is disabled. /// - public bool EnableScopeValidation { get; set; } + public bool DisableScopeValidation { get; set; } /// /// Gets the OAuth2/OpenID Connect flows enabled for this application. @@ -98,13 +105,6 @@ namespace OpenIddict.Server /// public RandomNumberGenerator RandomNumberGenerator { get; set; } = RandomNumberGenerator.Create(); - /// - /// Gets or sets a boolean determining whether client identification is required. - /// Enabling this option requires registering a client application and sending a - /// valid client_id when communicating with the token and revocation endpoints. - /// - public bool RequireClientIdentification { get; set; } - /// /// Gets the OAuth2/OpenID Connect scopes enabled for this application. /// diff --git a/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Authentication.cs b/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Authentication.cs index adef3266..1181ba82 100644 --- a/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Authentication.cs +++ b/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Authentication.cs @@ -205,8 +205,6 @@ namespace OpenIddict.Server.Tests It.IsAny())) .ReturnsAsync(ImmutableArray.Create()); })); - - builder.EnableScopeValidation(); }); var client = new OpenIdConnectClient(server.CreateClient()); @@ -257,7 +255,6 @@ namespace OpenIddict.Server.Tests .ReturnsAsync(true); })); - builder.EnableScopeValidation(); builder.RegisterScopes("registered_scope"); }); @@ -331,7 +328,6 @@ namespace OpenIddict.Server.Tests builder.RegisterScopes("scope_registered_in_options"); - builder.EnableScopeValidation(); builder.Services.AddSingleton(manager); }); diff --git a/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Exchange.cs b/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Exchange.cs index a43804c7..46447828 100644 --- a/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Exchange.cs +++ b/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Exchange.cs @@ -81,10 +81,7 @@ namespace OpenIddict.Server.Tests public async Task ValidateTokenRequest_AuthorizationCodeRequestIsRejectedWhenRedirectUriIsMissing() { // Arrange - var server = CreateAuthorizationServer(builder => - { - builder.EnableScopeValidation(); - }); + var server = CreateAuthorizationServer(); var client = new OpenIdConnectClient(server.CreateClient()); @@ -115,8 +112,6 @@ namespace OpenIddict.Server.Tests It.IsAny())) .ReturnsAsync(ImmutableArray.Create()); })); - - builder.EnableScopeValidation(); }); var client = new OpenIdConnectClient(server.CreateClient()); @@ -141,7 +136,6 @@ namespace OpenIddict.Server.Tests // Arrange var server = CreateAuthorizationServer(builder => { - builder.EnableScopeValidation(); builder.RegisterScopes("registered_scope"); }); @@ -182,7 +176,6 @@ namespace OpenIddict.Server.Tests var server = CreateAuthorizationServer(builder => { - builder.EnableScopeValidation(); builder.RegisterScopes("scope_registered_in_options"); builder.Services.AddSingleton(manager); @@ -254,7 +247,10 @@ namespace OpenIddict.Server.Tests public async Task ValidateTokenRequest_RequestWithoutClientIdIsRejectedWhenClientIdentificationIsRequired() { // Arrange - var server = CreateAuthorizationServer(builder => builder.RequireClientIdentification()); + var server = CreateAuthorizationServer(builder => + { + builder.Configure(options => options.AcceptAnonymousClients = false); + }); var client = new OpenIdConnectClient(server.CreateClient()); diff --git a/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Revocation.cs b/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Revocation.cs index 215437fc..6ea51325 100644 --- a/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Revocation.cs +++ b/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Revocation.cs @@ -49,7 +49,10 @@ namespace OpenIddict.Server.Tests public async Task ValidateRevocationRequest_RequestWithoutClientIdIsRejectedWhenClientIdentificationIsRequired() { // Arrange - var server = CreateAuthorizationServer(builder => builder.RequireClientIdentification()); + var server = CreateAuthorizationServer(builder => + { + builder.Configure(options => options.AcceptAnonymousClients = false); + }); var client = new OpenIdConnectClient(server.CreateClient()); diff --git a/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.cs b/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.cs index 18009f25..07ed1970 100644 --- a/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.cs +++ b/test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.cs @@ -1450,6 +1450,9 @@ namespace OpenIddict.Server.Tests .AddServer(options => { + // Accept anonymous clients by default. + options.AcceptAnonymousClients(); + // Disable the transport security requirement during testing. options.DisableHttpsRequirement(); diff --git a/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs b/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs index ac2c5441..e93abfd8 100644 --- a/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs +++ b/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs @@ -457,19 +457,19 @@ namespace OpenIddict.Server.Tests } [Fact] - public void EnableScopeValidation_ScopeValidationIsDisabled() + public void DisableScopeValidation_ScopeValidationIsDisabled() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.EnableScopeValidation(); + builder.DisableScopeValidation(); var options = GetOptions(services); // Assert - Assert.True(options.EnableScopeValidation); + Assert.True(options.DisableScopeValidation); } [Fact] @@ -505,19 +505,19 @@ namespace OpenIddict.Server.Tests } [Fact] - public void RequireClientIdentification_ClientIdentificationIsEnforced() + public void AcceptAnonymousClients_ClientIdentificationIsOptional() { // Arrange var services = CreateServices(); var builder = CreateBuilder(services); // Act - builder.RequireClientIdentification(); + builder.AcceptAnonymousClients(); var options = GetOptions(services); // Assert - Assert.True(options.RequireClientIdentification); + Assert.True(options.AcceptAnonymousClients); } [Fact]