Browse Source

Enable scope validation and reject unidentified token/revocation requests by default

pull/620/head
Kévin Chalet 8 years ago
parent
commit
8f9c6f109d
  1. 17
      samples/Mvc.Server/Startup.cs
  2. 2
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Authentication.cs
  3. 4
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Exchange.cs
  4. 2
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Revocation.cs
  5. 26
      src/OpenIddict.Server/OpenIddictServerBuilder.cs
  6. 18
      src/OpenIddict.Server/OpenIddictServerOptions.cs
  7. 4
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Authentication.cs
  8. 14
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Exchange.cs
  9. 5
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Revocation.cs
  10. 3
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.cs
  11. 12
      test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs

17
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.

2
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<string>(context.Request.GetScopes(), StringComparer.Ordinal);
scopes.ExceptWith(options.Scopes);

4
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<string>(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.");

2
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.");

26
src/OpenIddict.Server/OpenIddictServerBuilder.cs

@ -66,6 +66,14 @@ namespace Microsoft.Extensions.DependencyInjection
return this;
}
/// <summary>
/// Makes client identification optional so that token and revocation
/// requests that don't specify a client_id are not automatically rejected.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder AcceptAnonymousClients()
=> Configure(options => options.AcceptAnonymousClients = true);
/// <summary>
/// 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
}
/// <summary>
/// Rejects authorization and token requests that specify scopes that have not been
/// registered using <see cref="RegisterScopes(string[])"/> or the scope manager.
/// Allows processing authorization and token requests that specify scopes that have not
/// been registered using <see cref="RegisterScopes(string[])"/> or the scope manager.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder EnableScopeValidation()
=> Configure(options => options.EnableScopeValidation = true);
public OpenIddictServerBuilder DisableScopeValidation()
=> Configure(options => options.DisableScopeValidation = true);
/// <summary>
/// Enables the token endpoint.
@ -595,16 +603,6 @@ namespace Microsoft.Extensions.DependencyInjection
return Configure(options => options.Scopes.UnionWith(scopes));
}
/// <summary>
/// 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.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder RequireClientIdentification()
=> Configure(options => options.RequireClientIdentification = true);
/// <summary>
/// Sets the access token lifetime, after which client applications must retrieve
/// a new access token by making a grant_type=refresh_token token request

18
src/OpenIddict.Server/OpenIddictServerOptions.cs

@ -27,6 +27,13 @@ namespace OpenIddict.Server
ProviderType = typeof(OpenIddictServerProvider);
}
/// <summary>
/// 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.
/// </summary>
public bool AcceptAnonymousClients { get; set; }
/// <summary>
/// Gets or sets the user-provided <see cref="OpenIdConnectServerProvider"/> 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; }
/// <summary>
/// Gets or sets a boolean indicating whether scope validation is enabled.
/// Gets or sets a boolean indicating whether scope validation is disabled.
/// </summary>
public bool EnableScopeValidation { get; set; }
public bool DisableScopeValidation { get; set; }
/// <summary>
/// Gets the OAuth2/OpenID Connect flows enabled for this application.
@ -98,13 +105,6 @@ namespace OpenIddict.Server
/// </summary>
public RandomNumberGenerator RandomNumberGenerator { get; set; } = RandomNumberGenerator.Create();
/// <summary>
/// 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.
/// </summary>
public bool RequireClientIdentification { get; set; }
/// <summary>
/// Gets the OAuth2/OpenID Connect scopes enabled for this application.
/// </summary>

4
test/OpenIddict.Server.Tests/Internal/OpenIddictServerProviderTests.Authentication.cs

@ -205,8 +205,6 @@ namespace OpenIddict.Server.Tests
It.IsAny<CancellationToken>()))
.ReturnsAsync(ImmutableArray.Create<OpenIddictScope>());
}));
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);
});

14
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<CancellationToken>()))
.ReturnsAsync(ImmutableArray.Create<OpenIddictScope>());
}));
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());

5
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());

3
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();

12
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]

Loading…
Cancel
Save