|
|
@ -6,6 +6,7 @@ |
|
|
|
|
|
|
|
|
using System; |
|
|
using System; |
|
|
using System.Collections.Immutable; |
|
|
using System.Collections.Immutable; |
|
|
|
|
|
using System.Linq; |
|
|
using System.Security.Claims; |
|
|
using System.Security.Claims; |
|
|
using System.Text; |
|
|
using System.Text; |
|
|
using System.Threading.Tasks; |
|
|
using System.Threading.Tasks; |
|
|
@ -44,6 +45,7 @@ namespace OpenIddict.Server |
|
|
ValidateRedirectUriParameter.Descriptor, |
|
|
ValidateRedirectUriParameter.Descriptor, |
|
|
ValidateResponseTypeParameter.Descriptor, |
|
|
ValidateResponseTypeParameter.Descriptor, |
|
|
ValidateResponseModeParameter.Descriptor, |
|
|
ValidateResponseModeParameter.Descriptor, |
|
|
|
|
|
ValidateScopeParameter.Descriptor, |
|
|
ValidateNonceParameter.Descriptor, |
|
|
ValidateNonceParameter.Descriptor, |
|
|
ValidatePromptParameter.Descriptor, |
|
|
ValidatePromptParameter.Descriptor, |
|
|
ValidateCodeChallengeParameters.Descriptor, |
|
|
ValidateCodeChallengeParameters.Descriptor, |
|
|
@ -363,6 +365,12 @@ namespace OpenIddict.Server |
|
|
context.SkipRequest(); |
|
|
context.SkipRequest(); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
throw new InvalidOperationException(new StringBuilder() |
|
|
|
|
|
.Append("The authorization response was not correctly applied. To apply authorization response, ") |
|
|
|
|
|
.Append("create a class implementing 'IOpenIddictServerHandler<ApplyAuthorizationResponseContext>' ") |
|
|
|
|
|
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.") |
|
|
|
|
|
.ToString()); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -632,32 +640,10 @@ namespace OpenIddict.Server |
|
|
return default; |
|
|
return default; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Reject requests containing the id_token response_type if no openid scope has been received.
|
|
|
|
|
|
if (context.Request.HasResponseType(ResponseTypes.IdToken) && !context.Request.HasScope(Scopes.OpenId)) |
|
|
|
|
|
{ |
|
|
|
|
|
context.Logger.LogError("The authorization request was rejected because the 'openid' scope was missing."); |
|
|
|
|
|
|
|
|
|
|
|
context.Reject( |
|
|
|
|
|
error: Errors.InvalidRequest, |
|
|
|
|
|
description: "The mandatory 'openid' scope is missing."); |
|
|
|
|
|
|
|
|
|
|
|
return default; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Reject requests containing the code response_type if the token endpoint has been disabled.
|
|
|
|
|
|
if (context.Request.HasResponseType(ResponseTypes.Code) && context.Options.TokenEndpointUris.Count == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
context.Logger.LogError("The authorization request was rejected because the authorization code flow was disabled."); |
|
|
|
|
|
|
|
|
|
|
|
context.Reject( |
|
|
|
|
|
error: Errors.UnsupportedResponseType, |
|
|
|
|
|
description: "The specified 'response_type' is not supported by this server."); |
|
|
|
|
|
|
|
|
|
|
|
return default; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Reject requests that specify an unsupported response_type.
|
|
|
// Reject requests that specify an unsupported response_type.
|
|
|
if (!context.Request.IsAuthorizationCodeFlow() && !context.Request.IsHybridFlow() && !context.Request.IsImplicitFlow()) |
|
|
var types = context.Request.GetResponseTypes(); |
|
|
|
|
|
if (!context.Options.ResponseTypes.Any(type => |
|
|
|
|
|
types.SetEquals(type.Split(Separators.Space, StringSplitOptions.RemoveEmptyEntries)))) |
|
|
{ |
|
|
{ |
|
|
context.Logger.LogError("The authorization request was rejected because the '{ResponseType}' " + |
|
|
context.Logger.LogError("The authorization request was rejected because the '{ResponseType}' " + |
|
|
"response type is not supported.", context.Request.ResponseType); |
|
|
"response type is not supported.", context.Request.ResponseType); |
|
|
@ -669,71 +655,110 @@ namespace OpenIddict.Server |
|
|
return default; |
|
|
return default; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Reject code flow authorization requests if the authorization code flow is not enabled.
|
|
|
return default; |
|
|
if (context.Request.IsAuthorizationCodeFlow() && !context.Options.GrantTypes.Contains(GrantTypes.AuthorizationCode)) |
|
|
} |
|
|
{ |
|
|
} |
|
|
context.Logger.LogError("The authorization request was rejected because " + |
|
|
|
|
|
"the authorization code flow was not enabled."); |
|
|
|
|
|
|
|
|
|
|
|
context.Reject( |
|
|
/// <summary>
|
|
|
error: Errors.UnsupportedResponseType, |
|
|
/// Contains the logic responsible of rejecting authorization requests that specify an invalid response_mode parameter.
|
|
|
description: "The specified 'response_type' parameter is not allowed."); |
|
|
/// </summary>
|
|
|
|
|
|
public class ValidateResponseModeParameter : IOpenIddictServerHandler<ValidateAuthorizationRequestContext> |
|
|
|
|
|
{ |
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the default descriptor definition assigned to this handler.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static OpenIddictServerHandlerDescriptor Descriptor { get; } |
|
|
|
|
|
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateAuthorizationRequestContext>() |
|
|
|
|
|
.UseSingletonHandler<ValidateResponseModeParameter>() |
|
|
|
|
|
.SetOrder(ValidateResponseTypeParameter.Descriptor.Order + 1_000) |
|
|
|
|
|
.Build(); |
|
|
|
|
|
|
|
|
return default; |
|
|
/// <summary>
|
|
|
|
|
|
/// Processes the event.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="context">The context associated with the event to process.</param>
|
|
|
|
|
|
/// <returns>
|
|
|
|
|
|
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
|
|
|
|
|
|
/// </returns>
|
|
|
|
|
|
public ValueTask HandleAsync([NotNull] ValidateAuthorizationRequestContext context) |
|
|
|
|
|
{ |
|
|
|
|
|
if (context == null) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new ArgumentNullException(nameof(context)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Reject implicit flow authorization requests if the implicit flow is not enabled.
|
|
|
// response_mode=query (explicit or not) and a response_type containing id_token
|
|
|
if (context.Request.IsImplicitFlow() && !context.Options.GrantTypes.Contains(GrantTypes.Implicit)) |
|
|
// or token are not considered as a safe combination and MUST be rejected.
|
|
|
|
|
|
// See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Security.
|
|
|
|
|
|
if (context.Request.IsQueryResponseMode() && (context.Request.HasResponseType(ResponseTypes.IdToken) || |
|
|
|
|
|
context.Request.HasResponseType(ResponseTypes.Token))) |
|
|
{ |
|
|
{ |
|
|
context.Logger.LogError("The authorization request was rejected because the implicit flow was not enabled."); |
|
|
context.Logger.LogError("The authorization request was rejected because the 'response_type'/'response_mode' " + |
|
|
|
|
|
"combination was invalid: {ResponseType} ; {ResponseMode}.", |
|
|
|
|
|
context.Request.ResponseType, context.Request.ResponseMode); |
|
|
|
|
|
|
|
|
context.Reject( |
|
|
context.Reject( |
|
|
error: Errors.UnsupportedResponseType, |
|
|
error: Errors.InvalidRequest, |
|
|
description: "The specified 'response_type' parameter is not allowed."); |
|
|
description: "The specified 'response_type'/'response_mode' combination is invalid."); |
|
|
|
|
|
|
|
|
return default; |
|
|
return default; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Reject hybrid flow authorization requests if the authorization code or the implicit flows are not enabled.
|
|
|
// Reject requests that specify an unsupported response_mode or don't specify a different response_mode
|
|
|
if (context.Request.IsHybridFlow() && (!context.Options.GrantTypes.Contains(GrantTypes.AuthorizationCode) || |
|
|
// if the default response_mode inferred from the response_type was explicitly disabled in the options.
|
|
|
!context.Options.GrantTypes.Contains(GrantTypes.Implicit))) |
|
|
if (!ValidateResponseMode(context.Request, context.Options)) |
|
|
{ |
|
|
{ |
|
|
context.Logger.LogError("The authorization request was rejected because the " + |
|
|
context.Logger.LogError("The authorization request was rejected because the '{ResponseMode}' " + |
|
|
"authorization code flow or the implicit flow was not enabled."); |
|
|
"response mode is not supported.", context.Request.ResponseMode); |
|
|
|
|
|
|
|
|
context.Reject( |
|
|
context.Reject( |
|
|
error: Errors.UnsupportedResponseType, |
|
|
error: Errors.InvalidRequest, |
|
|
description: "The specified 'response_type' parameter is not allowed."); |
|
|
description: "The specified 'response_mode' parameter is not supported."); |
|
|
|
|
|
|
|
|
return default; |
|
|
return default; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Reject authorization requests that specify scope=offline_access if the refresh token flow is not enabled.
|
|
|
return default; |
|
|
if (context.Request.HasScope(Scopes.OfflineAccess) && !context.Options.GrantTypes.Contains(GrantTypes.RefreshToken)) |
|
|
|
|
|
|
|
|
static bool ValidateResponseMode(OpenIddictRequest request, OpenIddictServerOptions options) |
|
|
{ |
|
|
{ |
|
|
context.Reject( |
|
|
// Note: both the fragment and query response modes are used as default response modes
|
|
|
error: Errors.InvalidRequest, |
|
|
// when using the implicit/hybrid and code flows if no explicit value was set.
|
|
|
description: "The 'offline_access' scope is not allowed."); |
|
|
// To ensure requests are rejected if the default response mode was manually disabled,
|
|
|
|
|
|
// the fragment and query response modes are checked first using the appropriate extensions.
|
|
|
|
|
|
|
|
|
return default; |
|
|
if (request.IsFragmentResponseMode()) |
|
|
} |
|
|
{ |
|
|
|
|
|
return options.ResponseModes.Contains(ResponseModes.Fragment); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return default; |
|
|
if (request.IsQueryResponseMode()) |
|
|
|
|
|
{ |
|
|
|
|
|
return options.ResponseModes.Contains(ResponseModes.Query); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(request.ResponseMode)) |
|
|
|
|
|
{ |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return options.ResponseModes.Contains(request.ResponseMode); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Contains the logic responsible of rejecting authorization requests that specify an invalid response_mode parameter.
|
|
|
/// Contains the logic responsible of rejecting authorization requests that don't specify a valid scope parameter.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
public class ValidateResponseModeParameter : IOpenIddictServerHandler<ValidateAuthorizationRequestContext> |
|
|
public class ValidateScopeParameter : IOpenIddictServerHandler<ValidateAuthorizationRequestContext> |
|
|
{ |
|
|
{ |
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Gets the default descriptor definition assigned to this handler.
|
|
|
/// Gets the default descriptor definition assigned to this handler.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
public static OpenIddictServerHandlerDescriptor Descriptor { get; } |
|
|
public static OpenIddictServerHandlerDescriptor Descriptor { get; } |
|
|
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateAuthorizationRequestContext>() |
|
|
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateAuthorizationRequestContext>() |
|
|
.UseSingletonHandler<ValidateResponseModeParameter>() |
|
|
.UseSingletonHandler<ValidateScopeParameter>() |
|
|
.SetOrder(ValidateResponseTypeParameter.Descriptor.Order + 1_000) |
|
|
.SetOrder(ValidateResponseModeParameter.Descriptor.Order + 1_000) |
|
|
.Build(); |
|
|
.Build(); |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
@ -750,34 +775,24 @@ namespace OpenIddict.Server |
|
|
throw new ArgumentNullException(nameof(context)); |
|
|
throw new ArgumentNullException(nameof(context)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// response_mode=query (explicit or not) and a response_type containing id_token
|
|
|
// Reject authorization requests containing the id_token response_type if no openid scope has been received.
|
|
|
// or token are not considered as a safe combination and MUST be rejected.
|
|
|
if (context.Request.HasResponseType(ResponseTypes.IdToken) && !context.Request.HasScope(Scopes.OpenId)) |
|
|
// See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Security.
|
|
|
|
|
|
if (context.Request.IsQueryResponseMode() && (context.Request.HasResponseType(ResponseTypes.IdToken) || |
|
|
|
|
|
context.Request.HasResponseType(ResponseTypes.Token))) |
|
|
|
|
|
{ |
|
|
{ |
|
|
context.Logger.LogError("The authorization request was rejected because the 'response_type'/'response_mode' " + |
|
|
context.Logger.LogError("The authorization request was rejected because the 'openid' scope was missing."); |
|
|
"combination was invalid: {ResponseType} ; {ResponseMode}.", |
|
|
|
|
|
context.Request.ResponseType, context.Request.ResponseMode); |
|
|
|
|
|
|
|
|
|
|
|
context.Reject( |
|
|
context.Reject( |
|
|
error: Errors.InvalidRequest, |
|
|
error: Errors.InvalidRequest, |
|
|
description: "The specified 'response_type'/'response_mode' combination is invalid."); |
|
|
description: "The mandatory 'openid' scope is missing."); |
|
|
|
|
|
|
|
|
return default; |
|
|
return default; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Reject requests that specify an unsupported response_mode.
|
|
|
// Reject authorization requests that specify scope=offline_access if the refresh token flow is not enabled.
|
|
|
if (!string.IsNullOrEmpty(context.Request.ResponseMode) && !context.Request.IsFormPostResponseMode() && |
|
|
if (context.Request.HasScope(Scopes.OfflineAccess) && !context.Options.GrantTypes.Contains(GrantTypes.RefreshToken)) |
|
|
!context.Request.IsFragmentResponseMode() && |
|
|
|
|
|
!context.Request.IsQueryResponseMode()) |
|
|
|
|
|
{ |
|
|
{ |
|
|
context.Logger.LogError("The authorization request was rejected because the '{ResponseMode}' " + |
|
|
|
|
|
"response mode is not supported.", context.Request.ResponseMode); |
|
|
|
|
|
|
|
|
|
|
|
context.Reject( |
|
|
context.Reject( |
|
|
error: Errors.InvalidRequest, |
|
|
error: Errors.InvalidRequest, |
|
|
description: "The specified 'response_mode' parameter is not supported."); |
|
|
description: "The 'offline_access' scope is not allowed."); |
|
|
|
|
|
|
|
|
return default; |
|
|
return default; |
|
|
} |
|
|
} |
|
|
@ -797,7 +812,7 @@ namespace OpenIddict.Server |
|
|
public static OpenIddictServerHandlerDescriptor Descriptor { get; } |
|
|
public static OpenIddictServerHandlerDescriptor Descriptor { get; } |
|
|
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateAuthorizationRequestContext>() |
|
|
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateAuthorizationRequestContext>() |
|
|
.UseSingletonHandler<ValidateNonceParameter>() |
|
|
.UseSingletonHandler<ValidateNonceParameter>() |
|
|
.SetOrder(ValidateResponseModeParameter.Descriptor.Order + 1_000) |
|
|
.SetOrder(ValidateScopeParameter.Descriptor.Order + 1_000) |
|
|
.Build(); |
|
|
.Build(); |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
|