From 50eb0c94bd301e42d41ec4cb1a544e7554f600f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Thu, 29 Oct 2015 15:38:05 +0100 Subject: [PATCH] Reject authorization requests using the implicit/hybrid flow when the client is a confidential application --- src/OpenIddict.Core/OpenIddictProvider.cs | 61 +++++++++++++---------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/src/OpenIddict.Core/OpenIddictProvider.cs b/src/OpenIddict.Core/OpenIddictProvider.cs index ff1a0419..4bfcde1f 100644 --- a/src/OpenIddict.Core/OpenIddictProvider.cs +++ b/src/OpenIddict.Core/OpenIddictProvider.cs @@ -7,7 +7,6 @@ using System; using System.Diagnostics; using System.IdentityModel.Tokens.Jwt; -using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using AspNet.Security.OpenIdConnect.Extensions; @@ -101,9 +100,9 @@ namespace OpenIddict { return; } - // Retrieve the application details corresponding to the requested client_id. var manager = context.HttpContext.RequestServices.GetRequiredService>(); + // Retrieve the application details corresponding to the requested client_id. var application = await manager.FindApplicationByIdAsync(context.ClientId); if (application == null) { context.Rejected( @@ -138,40 +137,52 @@ namespace OpenIddict { } public override async Task ValidateAuthorizationRequest([NotNull] ValidateAuthorizationRequestContext context) { - // Only validate prompt=none requests at this stage. - if (!string.Equals(context.Request.Prompt, "none", StringComparison.Ordinal)) { - return; - } + var manager = context.HttpContext.RequestServices.GetRequiredService>(); - // Extract the principal contained in the id_token_hint parameter. - // If no principal can be extracted, an error is returned to the client application. - var principal = await context.HttpContext.Authentication.AuthenticateAsync(context.Options.AuthenticationScheme); - if (principal == null) { + // Retrieve the application details corresponding to the requested client_id. + var application = await manager.FindApplicationByIdAsync(context.ClientContext.ClientId); + Debug.Assert(application != null); + + // To prevent downgrade attacks, ensure that authorization requests using the hybrid/implicit + // flow are rejected if the client identifier corresponds to a confidential application. + var type = await manager.GetApplicationTypeAsync(application); + if (type == OpenIddictConstants.ApplicationTypes.Confidential && !context.Request.IsAuthorizationCodeFlow()) { context.Rejected( error: OpenIdConnectConstants.Errors.InvalidRequest, - description: "The required id_token_hint parameter is missing"); + description: "Confidential clients can only use response_type=code."); return; } - if (!string.Equals(principal.FindFirstValue(JwtRegisteredClaimNames.Aud), context.Request.ClientId)) { - context.Rejected( - error: OpenIdConnectConstants.Errors.InvalidRequest, - description: "The id_token_hint parameter is invalid"); + if (string.Equals(context.Request.Prompt, "none", StringComparison.Ordinal)) { + // Extract the principal contained in the id_token_hint parameter. + // If no principal can be extracted, an error is returned to the client application. + var principal = await context.HttpContext.Authentication.AuthenticateAsync(context.Options.AuthenticationScheme); + if (principal == null) { + context.Rejected( + error: OpenIdConnectConstants.Errors.InvalidRequest, + description: "The required id_token_hint parameter is missing"); - return; - } + return; + } - var manager = context.HttpContext.RequestServices.GetRequiredService>(); + if (!string.Equals(principal.FindFirstValue(JwtRegisteredClaimNames.Aud), context.Request.ClientId)) { + context.Rejected( + error: OpenIdConnectConstants.Errors.InvalidRequest, + description: "The id_token_hint parameter is invalid"); - // Ensure the user still exists. - var user = await manager.FindByIdAsync(principal.GetUserId()); - if (user == null) { - context.Rejected( - error: OpenIdConnectConstants.Errors.InvalidRequest, - description: "The id_token_hint parameter is invalid"); + return; + } - return; + // Ensure the user still exists. + var user = await manager.FindByIdAsync(principal.GetUserId()); + if (user == null) { + context.Rejected( + error: OpenIdConnectConstants.Errors.InvalidRequest, + description: "The id_token_hint parameter is invalid"); + + return; + } } }