From 673caa409d834900db5532e27460abea282058ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Sat, 30 Jul 2016 20:13:49 +0200 Subject: [PATCH] Introduce OpenIddictBuilder.RequireClientIdentification() --- samples/Mvc.Server/Startup.cs | 3 +++ .../Infrastructure/OpenIddictProvider.Exchange.cs | 15 ++++++++++++++- .../OpenIddictProvider.Revocation.cs | 15 ++++++++++++++- src/OpenIddict.Core/OpenIddictBuilder.cs | 10 ++++++++++ src/OpenIddict.Core/OpenIddictOptions.cs | 8 +++++++- 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/samples/Mvc.Server/Startup.cs b/samples/Mvc.Server/Startup.cs index 256ccc13..4aeb6a95 100644 --- a/samples/Mvc.Server/Startup.cs +++ b/samples/Mvc.Server/Startup.cs @@ -48,6 +48,9 @@ namespace Mvc.Server { .AllowPasswordFlow() .AllowRefreshTokenFlow() + // Make the "client_id" parameter mandatory when sending a token request. + .RequireClientIdentification() + // During development, you can disable the HTTPS requirement. .DisableHttpsRequirement() diff --git a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs index 4d830820..24921c9e 100644 --- a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs +++ b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs @@ -79,11 +79,24 @@ namespace OpenIddict.Infrastructure { // See http://openid.net/specs/openid-connect-core-1_0.html#RefreshingAccessToken // and https://tools.ietf.org/html/rfc6749#section-6 for more information. - // At this stage, skip client authentication if the client identifier is missing. + // At this stage, skip client authentication if the client identifier is missing + // or reject the token request if client identification is set as required. // Note: the OpenID Connect server middleware will automatically ensure that // the calling application cannot use an authorization code or a refresh token // if it's not the intended audience, even if client authentication was skipped. if (string.IsNullOrEmpty(context.ClientId)) { + // Reject the request if client identification is mandatory. + if (services.Options.RequireClientIdentification) { + services.Logger.LogError("The token request was rejected becaused the " + + "mandatory client_id parameter was missing or empty."); + + context.Reject( + error: OpenIdConnectConstants.Errors.InvalidRequest, + description: "The mandatory 'client_id' parameter was missing."); + + return; + } + services.Logger.LogInformation("The token request validation process was skipped " + "because the client_id parameter was missing or empty."); diff --git a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Revocation.cs b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Revocation.cs index 9c24f466..c0da2164 100644 --- a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Revocation.cs +++ b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Revocation.cs @@ -31,11 +31,24 @@ namespace OpenIddict.Infrastructure { return; } - // Skip client authentication if the client identifier is missing. + // Skip client authentication if the client identifier is missing or reject + // the revocation request if client identification is set as required. // Note: the OpenID Connect server middleware will automatically ensure that // the calling application cannot revoke a refresh token if it's not // the intended audience, even if client authentication was skipped. if (string.IsNullOrEmpty(context.ClientId)) { + // Reject the request if client identification is mandatory. + if (services.Options.RequireClientIdentification) { + services.Logger.LogError("The revocation request was rejected becaused the " + + "mandatory client_id parameter was missing or empty."); + + context.Reject( + error: OpenIdConnectConstants.Errors.InvalidRequest, + description: "The mandatory 'client_id' parameter was missing."); + + return; + } + services.Logger.LogInformation("The revocation request validation process was skipped " + "because the client_id parameter was missing or empty."); diff --git a/src/OpenIddict.Core/OpenIddictBuilder.cs b/src/OpenIddict.Core/OpenIddictBuilder.cs index b6f1a638..60886652 100644 --- a/src/OpenIddict.Core/OpenIddictBuilder.cs +++ b/src/OpenIddict.Core/OpenIddictBuilder.cs @@ -573,6 +573,16 @@ namespace Microsoft.AspNetCore.Builder { return Configure(options => options.UserinfoEndpointPath = path); } + /// + /// 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. + /// + public virtual OpenIddictBuilder RequireClientIdentification() { + return 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.Core/OpenIddictOptions.cs b/src/OpenIddict.Core/OpenIddictOptions.cs index 5f4d2cf4..3d156175 100644 --- a/src/OpenIddict.Core/OpenIddictOptions.cs +++ b/src/OpenIddict.Core/OpenIddictOptions.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using AspNet.Security.OpenIdConnect.Server; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Caching.Distributed; namespace OpenIddict { @@ -36,5 +35,12 @@ namespace OpenIddict { /// Gets the list of the OpenIddict modules registered in the application. /// public ICollection Modules { get; } = new List(); + + /// + /// 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; } } }