From 37e08b20d9bb4bda9109b6101df8f3c7c70b4e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Mon, 9 Sep 2019 13:05:25 +0200 Subject: [PATCH] Update the authorization/logout endpoints to automatically validate id_token_hint and refactor HandleAuthenticateAsync()/AuthenticateCoreAsync() --- .../OpenIddictServerAspNetCoreHandler.cs | 170 ++++------------- .../OpenIddictServerOwinHandler.cs | 172 +++--------------- .../OpenIddictServerConstants.cs | 2 +- .../OpenIddictServerEvents.cs | 37 +++- .../OpenIddictServerHandlerFilters.cs | 16 +- ...OpenIddictServerHandlers.Authentication.cs | 136 ++++++++++---- .../OpenIddictServerHandlers.Exchange.cs | 28 +-- .../OpenIddictServerHandlers.Introspection.cs | 44 +---- .../OpenIddictServerHandlers.Session.cs | 74 +++++++- .../OpenIddictServerHandlers.Userinfo.cs | 15 +- .../OpenIddictServerHandlers.cs | 154 +++++++++------- 11 files changed, 358 insertions(+), 490 deletions(-) diff --git a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs index 7a30b64c..5ce77d1d 100644 --- a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs +++ b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs @@ -114,157 +114,57 @@ namespace OpenIddict.Server.AspNetCore throw new InvalidOperationException("An identity cannot be extracted from this request."); } - switch (transaction.EndpointType) - { - case OpenIddictServerEndpointType.Authorization: - case OpenIddictServerEndpointType.Logout: - { - if (string.IsNullOrEmpty(transaction.Request.IdTokenHint)) - { - return AuthenticateResult.NoResult(); - } - - var notification = new DeserializeIdentityTokenContext(transaction) - { - Token = transaction.Request.IdTokenHint - }; - - await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The identity token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating identity tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - - if (notification.Principal == null) - { - return AuthenticateResult.Fail("The identity token is not valid."); - } + var context = new ProcessAuthenticationContext(transaction); + await _provider.DispatchAsync(context); - // Note: tickets are returned even if they are considered invalid (e.g expired). + if (context.Principal == null || context.IsRequestHandled || context.IsRequestSkipped) + { + return AuthenticateResult.NoResult(); + } - return AuthenticateResult.Success(new AuthenticationTicket( - notification.Principal, - OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); - } + else if (context.IsRejected) + { + var builder = new StringBuilder(); - case OpenIddictServerEndpointType.Token when transaction.Request.IsAuthorizationCodeGrantType(): + if (!string.IsNullOrEmpty(context.Error)) { - // Note: this method can be called from the ApplyTokenResponse event, - // which may be invoked for a missing authorization code/refresh token. - if (string.IsNullOrEmpty(transaction.Request.Code)) - { - return AuthenticateResult.NoResult(); - } + builder.AppendLine("An error occurred while authenticating the current request:"); + builder.AppendFormat("Error code: ", context.Error); - var notification = new DeserializeAuthorizationCodeContext(transaction) + if (!string.IsNullOrEmpty(context.ErrorDescription)) { - Token = transaction.Request.Code - }; - - await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The authorization code was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating authorization codes ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); + builder.AppendLine(); + builder.AppendFormat("Error description: ", context.ErrorDescription); } - if (notification.Principal == null) + if (!string.IsNullOrEmpty(context.ErrorUri)) { - return AuthenticateResult.Fail("The authorization code is not valid."); + builder.AppendLine(); + builder.AppendFormat("Error URI: ", context.ErrorUri); } - - // Note: tickets are returned even if they are considered invalid (e.g expired). - - return AuthenticateResult.Success(new AuthenticationTicket( - notification.Principal, - OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); } - case OpenIddictServerEndpointType.Token when transaction.Request.IsRefreshTokenGrantType(): + else { - if (string.IsNullOrEmpty(transaction.Request.RefreshToken)) - { - return AuthenticateResult.NoResult(); - } - - var notification = new DeserializeRefreshTokenContext(transaction) - { - Token = transaction.Request.RefreshToken - }; - - await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The refresh token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating refresh tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - - if (notification.Principal == null) - { - return AuthenticateResult.Fail("The refresh token is not valid."); - } - - // Note: tickets are returned even if they are considered invalid (e.g expired). - - return AuthenticateResult.Success(new AuthenticationTicket( - notification.Principal, - OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); + builder.Append("An unknown error occurred while authenticating the current request."); } - case OpenIddictServerEndpointType.Userinfo: + return AuthenticateResult.Fail(new Exception(builder.ToString()) { - if (string.IsNullOrEmpty(transaction.Request.AccessToken)) + // Note: the error details are stored as additional exception properties, + // which is similar to what other ASP.NET Core security handlers do. + Data = { - return AuthenticateResult.NoResult(); + [Parameters.Error] = context.Error, + [Parameters.ErrorDescription] = context.ErrorDescription, + [Parameters.ErrorUri] = context.ErrorUri } - - var notification = new DeserializeAccessTokenContext(transaction) - { - Token = transaction.Request.AccessToken - }; - - await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The access token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating access tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - - if (notification.Principal == null) - { - return AuthenticateResult.Fail("The access token is not valid."); - } - - var date = notification.Principal.GetExpirationDate(); - if (date.HasValue && date.Value < DateTimeOffset.UtcNow) - { - return AuthenticateResult.Fail("The access token is no longer valid."); - } - - return AuthenticateResult.Success(new AuthenticationTicket( - notification.Principal, - OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); - } - - default: throw new InvalidOperationException("An identity cannot be extracted from this request."); + }); } + + return AuthenticateResult.Success(new AuthenticationTicket( + context.Principal, + OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); } protected override async Task HandleChallengeAsync([CanBeNull] AuthenticationProperties properties) @@ -275,7 +175,7 @@ namespace OpenIddict.Server.AspNetCore throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint."); } - var context = new ProcessChallengeResponseContext(transaction) + var context = new ProcessChallengeContext(transaction) { Response = new OpenIddictResponse { @@ -338,7 +238,7 @@ namespace OpenIddict.Server.AspNetCore throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint."); } - var context = new ProcessSigninResponseContext(transaction) + var context = new ProcessSigninContext(transaction) { Principal = user, Response = new OpenIddictResponse() @@ -386,7 +286,7 @@ namespace OpenIddict.Server.AspNetCore throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint."); } - var context = new ProcessSignoutResponseContext(transaction) + var context = new ProcessSignoutContext(transaction) { Response = new OpenIddictResponse() }; diff --git a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs index f7fc1b0a..2021fd3d 100644 --- a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs +++ b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs @@ -112,160 +112,32 @@ namespace OpenIddict.Server.Owin throw new InvalidOperationException("An identity cannot be extracted from this request."); } - switch (transaction.EndpointType) - { - case OpenIddictServerEndpointType.Authorization: - case OpenIddictServerEndpointType.Logout: - { - if (string.IsNullOrEmpty(transaction.Request.IdTokenHint)) - { - return null; - } - - var notification = new DeserializeIdentityTokenContext(transaction) - { - Token = transaction.Request.IdTokenHint - }; - - await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The identity token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating identity tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - - if (notification.Principal == null) - { - _logger.LogWarning("The identity token extracted from the 'id_token_hint' " + - "parameter was invalid or malformed and was ignored."); - - return null; - } - - // Tickets are returned even if they are considered invalid (e.g expired). - - return new AuthenticationTicket((ClaimsIdentity) notification.Principal.Identity, new AuthenticationProperties()); - } - - case OpenIddictServerEndpointType.Token when transaction.Request.IsAuthorizationCodeGrantType(): - { - // Note: this method can be called from the ApplyTokenResponse event, - // which may be invoked for a missing authorization code/refresh token. - if (string.IsNullOrEmpty(transaction.Request.Code)) - { - return null; - } - - var notification = new DeserializeAuthorizationCodeContext(transaction) - { - Token = transaction.Request.Code - }; - - await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The authorization code was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating authorization codes ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - - if (notification.Principal == null) - { - _logger.LogWarning("The authorization code extracted from the token request was invalid and was ignored."); - - return null; - } - - // Tickets are returned even if they are considered invalid (e.g expired). - - return new AuthenticationTicket((ClaimsIdentity) notification.Principal.Identity, new AuthenticationProperties()); - } - - case OpenIddictServerEndpointType.Token when transaction.Request.IsRefreshTokenGrantType(): - { - if (string.IsNullOrEmpty(transaction.Request.RefreshToken)) - { - return null; - } - - var notification = new DeserializeRefreshTokenContext(transaction) - { - Token = transaction.Request.RefreshToken - }; - - await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The refresh token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating refresh tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - - if (notification.Principal == null) - { - _logger.LogWarning("The refresh token extracted from the token request was invalid and was ignored."); - - return null; - } + var context = new ProcessAuthenticationContext(transaction); + await _provider.DispatchAsync(context); - // Tickets are returned even if they are considered invalid (e.g expired). + if (context.Principal == null || context.IsRequestHandled || context.IsRequestSkipped) + { + return null; + } - return new AuthenticationTicket((ClaimsIdentity) notification.Principal.Identity, new AuthenticationProperties()); - } + else if (context.IsRejected) + { + _logger.LogError("An error occurred while authenticating the current request: {Error} ; {Description}", + /* Error: */ context.Error ?? Errors.InvalidToken, + /* Description: */ context.ErrorDescription); - case OpenIddictServerEndpointType.Userinfo: + return new AuthenticationTicket(identity: null, new AuthenticationProperties { - if (string.IsNullOrEmpty(transaction.Request.AccessToken)) + Dictionary = { - return null; + [Parameters.Error] = context.Error, + [Parameters.ErrorDescription] = context.ErrorDescription, + [Parameters.ErrorUri] = context.ErrorUri } - - var notification = new DeserializeAccessTokenContext(transaction) - { - Token = transaction.Request.AccessToken - }; - - await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The access token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating access tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - - if (notification.Principal == null) - { - _logger.LogWarning("The access token extracted from the userinfo request was invalid and was ignored."); - - return null; - } - - var date = notification.Principal.GetExpirationDate(); - if (date.HasValue && date.Value < DateTimeOffset.UtcNow) - { - _logger.LogError("The access token extracted from the userinfo request was expired."); - - return null; - } - - return new AuthenticationTicket((ClaimsIdentity) notification.Principal.Identity, new AuthenticationProperties()); - } - - default: throw new InvalidOperationException("An identity cannot be extracted from this request."); + }); } + + return new AuthenticationTicket((ClaimsIdentity) context.Principal.Identity, new AuthenticationProperties()); } protected override async Task TeardownCoreAsync() @@ -291,7 +163,7 @@ namespace OpenIddict.Server.Owin throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint."); } - var context = new ProcessChallengeResponseContext(transaction) + var context = new ProcessChallengeContext(transaction) { Response = new OpenIddictResponse { @@ -347,7 +219,7 @@ namespace OpenIddict.Server.Owin throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint."); } - var context = new ProcessSigninResponseContext(transaction) + var context = new ProcessSigninContext(transaction) { Principal = signin.Principal, Response = new OpenIddictResponse() @@ -396,7 +268,7 @@ namespace OpenIddict.Server.Owin throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint."); } - var context = new ProcessSignoutResponseContext(transaction) + var context = new ProcessSignoutContext(transaction) { Response = new OpenIddictResponse() }; diff --git a/src/OpenIddict.Server/OpenIddictServerConstants.cs b/src/OpenIddict.Server/OpenIddictServerConstants.cs index 4f261a2e..60a62662 100644 --- a/src/OpenIddict.Server/OpenIddictServerConstants.cs +++ b/src/OpenIddict.Server/OpenIddictServerConstants.cs @@ -10,7 +10,7 @@ namespace OpenIddict.Server { public static class Properties { - public const string Principal = ".principal"; + public const string AmbientPrincipal = ".ambient_principal"; public const string ValidatedPostLogoutRedirectUri = ".validated_post_logout_redirect_uri"; public const string ValidatedRedirectUri = ".validated_redirect_uri"; } diff --git a/src/OpenIddict.Server/OpenIddictServerEvents.cs b/src/OpenIddict.Server/OpenIddictServerEvents.cs index 363c4c7c..216974ce 100644 --- a/src/OpenIddict.Server/OpenIddictServerEvents.cs +++ b/src/OpenIddict.Server/OpenIddictServerEvents.cs @@ -285,15 +285,34 @@ namespace OpenIddict.Server } } + /// + /// Represents an event called when processing an authentication operation. + /// + public class ProcessAuthenticationContext : BaseValidatingContext + { + /// + /// Creates a new instance of the class. + /// + public ProcessAuthenticationContext([NotNull] OpenIddictServerTransaction transaction) + : base(transaction) + { + } + + /// + /// Gets or sets the security principal. + /// + public ClaimsPrincipal Principal { get; set; } + } + /// /// Represents an event called when processing a challenge response. /// - public class ProcessChallengeResponseContext : BaseValidatingContext + public class ProcessChallengeContext : BaseValidatingContext { /// - /// Creates a new instance of the class. + /// Creates a new instance of the class. /// - public ProcessChallengeResponseContext([NotNull] OpenIddictServerTransaction transaction) + public ProcessChallengeContext([NotNull] OpenIddictServerTransaction transaction) : base(transaction) { } @@ -302,12 +321,12 @@ namespace OpenIddict.Server /// /// Represents an event called when processing a sign-in response. /// - public class ProcessSigninResponseContext : BaseValidatingTicketContext + public class ProcessSigninContext : BaseValidatingTicketContext { /// - /// Creates a new instance of the class. + /// Creates a new instance of the class. /// - public ProcessSigninResponseContext([NotNull] OpenIddictServerTransaction transaction) + public ProcessSigninContext([NotNull] OpenIddictServerTransaction transaction) : base(transaction) { } @@ -348,12 +367,12 @@ namespace OpenIddict.Server /// /// Represents an event called when processing a sign-out response. /// - public class ProcessSignoutResponseContext : BaseValidatingContext + public class ProcessSignoutContext : BaseValidatingContext { /// - /// Creates a new instance of the class. + /// Creates a new instance of the class. /// - public ProcessSignoutResponseContext([NotNull] OpenIddictServerTransaction transaction) + public ProcessSignoutContext([NotNull] OpenIddictServerTransaction transaction) : base(transaction) { } diff --git a/src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs b/src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs index b3033b35..fcb5924d 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs @@ -18,9 +18,9 @@ namespace OpenIddict.Server /// /// Represents a filter that excludes the associated handlers if no access token is returned. /// - public class RequireAccessTokenIncluded : IOpenIddictServerHandlerFilter + public class RequireAccessTokenIncluded : IOpenIddictServerHandlerFilter { - public ValueTask IsActiveAsync([NotNull] ProcessSigninResponseContext context) + public ValueTask IsActiveAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -34,9 +34,9 @@ namespace OpenIddict.Server /// /// Represents a filter that excludes the associated handlers if no authorization code is returned. /// - public class RequireAuthorizationCodeIncluded : IOpenIddictServerHandlerFilter + public class RequireAuthorizationCodeIncluded : IOpenIddictServerHandlerFilter { - public ValueTask IsActiveAsync([NotNull] ProcessSigninResponseContext context) + public ValueTask IsActiveAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -114,9 +114,9 @@ namespace OpenIddict.Server /// /// Represents a filter that excludes the associated handlers if no identity token is returned. /// - public class RequireIdentityTokenIncluded : IOpenIddictServerHandlerFilter + public class RequireIdentityTokenIncluded : IOpenIddictServerHandlerFilter { - public ValueTask IsActiveAsync([NotNull] ProcessSigninResponseContext context) + public ValueTask IsActiveAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -146,9 +146,9 @@ namespace OpenIddict.Server /// /// Represents a filter that excludes the associated handlers if no refresh token is returned. /// - public class RequireRefreshTokenIncluded : IOpenIddictServerHandlerFilter + public class RequireRefreshTokenIncluded : IOpenIddictServerHandlerFilter { - public ValueTask IsActiveAsync([NotNull] ProcessSigninResponseContext context) + public ValueTask IsActiveAsync([NotNull] ProcessSigninContext context) { if (context == null) { diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs index a4d34a37..76705003 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs @@ -29,10 +29,10 @@ namespace OpenIddict.Server ExtractAuthorizationRequest.Descriptor, ValidateAuthorizationRequest.Descriptor, HandleAuthorizationRequest.Descriptor, - ApplyAuthorizationResponse.Descriptor, + ApplyAuthorizationResponse.Descriptor, ApplyAuthorizationResponse.Descriptor, ApplyAuthorizationResponse.Descriptor, - ApplyAuthorizationResponse.Descriptor, + ApplyAuthorizationResponse.Descriptor, /* * Authorization request validation: @@ -46,6 +46,7 @@ namespace OpenIddict.Server ValidateNonceParameter.Descriptor, ValidatePromptParameter.Descriptor, ValidateCodeChallengeParameters.Descriptor, + ValidateIdTokenHint.Descriptor, ValidateClientId.Descriptor, ValidateClientType.Descriptor, ValidateClientRedirectUri.Descriptor, @@ -274,7 +275,7 @@ namespace OpenIddict.Server if (notification.Principal != null) { - var @event = new ProcessSigninResponseContext(context.Transaction) + var @event = new ProcessSigninContext(context.Transaction) { Principal = notification.Principal, Response = new OpenIddictResponse() @@ -971,32 +972,21 @@ namespace OpenIddict.Server } /// - /// Contains the logic responsible of rejecting authorization requests that use unregistered scopes. - /// Note: this handler is not used when the degraded mode is enabled or when scope validation is disabled. + /// Contains the logic responsible of rejecting authorization requests that don't specify a valid id_token_hint. /// - public class ValidateScopes : IOpenIddictServerHandler + public class ValidateIdTokenHint : IOpenIddictServerHandler { - private readonly IOpenIddictScopeManager _scopeManager; - - public ValidateScopes() => throw new InvalidOperationException(new StringBuilder() - .AppendLine("The core services must be registered when enabling the OpenIddict server feature.") - .Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ") - .AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.") - .Append("Alternatively, you can disable the built-in database-based server features by enabling ") - .Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.") - .ToString()); + private readonly IOpenIddictServerProvider _provider; - public ValidateScopes([NotNull] IOpenIddictScopeManager scopeManager) - => _scopeManager = scopeManager; + public ValidateIdTokenHint([NotNull] IOpenIddictServerProvider provider) + => _provider = provider; /// /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() - .AddFilter() - .UseScopedHandler() + .UseScopedHandler() .SetOrder(ValidateCodeChallengeParameters.Descriptor.Order + 1_000) .Build(); @@ -1014,28 +1004,31 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - // If all the specified scopes are registered in the options, avoid making a database lookup. - var scopes = context.Request.GetScopes().Except(context.Options.Scopes); - if (scopes.Count != 0) + if (string.IsNullOrEmpty(context.Request.IdTokenHint)) { - await foreach (var scope in _scopeManager.FindByNamesAsync(scopes.ToImmutableArray())) - { - scopes = scopes.Remove(await _scopeManager.GetNameAsync(scope)); - } + return; } - // If at least one scope was not recognized, return an error. - if (scopes.Count != 0) + var notification = new DeserializeIdentityTokenContext(context.Transaction) { - context.Logger.LogError("The authentication request was rejected because " + - "invalid scopes were specified: {Scopes}.", scopes); + Token = context.Request.IdTokenHint + }; + await _provider.DispatchAsync(notification); + + if (notification.Principal == null) + { context.Reject( - error: Errors.InvalidScope, - description: "The specified 'scope' parameter is not valid."); + error: Errors.InvalidRequest, + description: "The specified 'id_token_hint' parameter is invalid or malformed."); return; } + + // Note: the expiration date associated with an identity token used as an id_token_hint is deliberately ignored. + + // Store the security principal extracted from the identity token as an environment property. + context.Transaction.Properties[Properties.AmbientPrincipal] = notification.Principal; } } @@ -1065,7 +1058,7 @@ namespace OpenIddict.Server = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .UseScopedHandler() - .SetOrder(ValidateScopes.Descriptor.Order + 1_000) + .SetOrder(ValidateIdTokenHint.Descriptor.Order + 1_000) .Build(); /// @@ -1229,6 +1222,75 @@ namespace OpenIddict.Server } } + /// + /// Contains the logic responsible of rejecting authorization requests that use unregistered scopes. + /// Note: this handler is not used when the degraded mode is enabled or when scope validation is disabled. + /// + public class ValidateScopes : IOpenIddictServerHandler + { + private readonly IOpenIddictScopeManager _scopeManager; + + public ValidateScopes() => throw new InvalidOperationException(new StringBuilder() + .AppendLine("The core services must be registered when enabling the OpenIddict server feature.") + .Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ") + .AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.") + .Append("Alternatively, you can disable the built-in database-based server features by enabling ") + .Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.") + .ToString()); + + public ValidateScopes([NotNull] IOpenIddictScopeManager scopeManager) + => _scopeManager = scopeManager; + + /// + /// Gets the default descriptor definition assigned to this handler. + /// + public static OpenIddictServerHandlerDescriptor Descriptor { get; } + = OpenIddictServerHandlerDescriptor.CreateBuilder() + .AddFilter() + .AddFilter() + .UseScopedHandler() + .SetOrder(ValidateClientRedirectUri.Descriptor.Order + 1_000) + .Build(); + + /// + /// Processes the event. + /// + /// The context associated with the event to process. + /// + /// A that can be used to monitor the asynchronous operation. + /// + public async ValueTask HandleAsync([NotNull] ValidateAuthorizationRequestContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + // If all the specified scopes are registered in the options, avoid making a database lookup. + var scopes = context.Request.GetScopes().Except(context.Options.Scopes); + if (scopes.Count != 0) + { + await foreach (var scope in _scopeManager.FindByNamesAsync(scopes.ToImmutableArray())) + { + scopes = scopes.Remove(await _scopeManager.GetNameAsync(scope)); + } + } + + // If at least one scope was not recognized, return an error. + if (scopes.Count != 0) + { + context.Logger.LogError("The authentication request was rejected because " + + "invalid scopes were specified: {Scopes}.", scopes); + + context.Reject( + error: Errors.InvalidScope, + description: "The specified 'scope' parameter is not valid."); + + return; + } + } + } + /// /// Contains the logic responsible of rejecting authorization requests made by unauthorized applications. /// Note: this handler is not used when the degraded mode is enabled or when endpoint permissions are disabled. @@ -1256,7 +1318,7 @@ namespace OpenIddict.Server .AddFilter() .AddFilter() .UseScopedHandler() - .SetOrder(ValidateClientRedirectUri.Descriptor.Order + 1_000) + .SetOrder(ValidateScopes.Descriptor.Order + 1_000) .Build(); /// @@ -1515,9 +1577,9 @@ namespace OpenIddict.Server // Note: at this stage, the validated redirect URI property may be null (e.g if an error // is returned from the ExtractAuthorizationRequest/ValidateAuthorizationRequest events). - if (context.Transaction.Properties.TryGetValue(Properties.ValidatedRedirectUri, out var property)) + if (context.Transaction.Properties.TryGetValue(Properties.ValidatedRedirectUri, out var address)) { - context.RedirectUri = (string) property; + context.RedirectUri = (string) address; } return default; diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs index bf444e06..402bf6a1 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs @@ -33,10 +33,10 @@ namespace OpenIddict.Server ExtractTokenRequest.Descriptor, ValidateTokenRequest.Descriptor, HandleTokenRequest.Descriptor, - ApplyTokenResponse.Descriptor, + ApplyTokenResponse.Descriptor, ApplyTokenResponse.Descriptor, ApplyTokenResponse.Descriptor, - ApplyTokenResponse.Descriptor, + ApplyTokenResponse.Descriptor, /* * Token request validation: @@ -204,7 +204,7 @@ namespace OpenIddict.Server } // Store the security principal extracted from the authorization code/refresh token as an environment property. - context.Transaction.Properties[Properties.Principal] = notification.Principal; + context.Transaction.Properties[Properties.AmbientPrincipal] = notification.Principal; context.Logger.LogInformation("The token request was successfully validated."); } @@ -274,7 +274,7 @@ namespace OpenIddict.Server if (notification.Principal != null) { - var @event = new ProcessSigninResponseContext(context.Transaction) + var @event = new ProcessSigninContext(context.Transaction) { Principal = notification.Principal, Response = new OpenIddictResponse() @@ -1233,15 +1233,6 @@ namespace OpenIddict.Server await _provider.DispatchAsync(notification); - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The authorization code was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating authorization codes ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - if (notification.Principal == null) { context.Logger.LogError("The token request was rejected because the authorization code was invalid."); @@ -1315,15 +1306,6 @@ namespace OpenIddict.Server await _provider.DispatchAsync(notification); - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The refresh token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating refresh tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - if (notification.Principal == null) { context.Logger.LogError("The token request was rejected because the refresh token was invalid."); @@ -1739,7 +1721,7 @@ namespace OpenIddict.Server return default; } - if (context.Transaction.Properties.TryGetValue(Properties.Principal, out var principal)) + if (context.Transaction.Properties.TryGetValue(Properties.AmbientPrincipal, out var principal)) { context.Principal ??= (ClaimsPrincipal) principal; } diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs index 4c366dd7..a395884a 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs @@ -199,7 +199,7 @@ namespace OpenIddict.Server } // Store the security principal extracted from the introspected token as an environment property. - context.Transaction.Properties[Properties.Principal] = notification.Principal; + context.Transaction.Properties[Properties.AmbientPrincipal] = notification.Principal; context.Logger.LogInformation("The introspection request was successfully validated."); } @@ -767,16 +767,6 @@ namespace OpenIddict.Server }; await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The access token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating access tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - return notification.Principal; } @@ -788,16 +778,6 @@ namespace OpenIddict.Server }; await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The authorization code was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating authorization codes ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - return notification.Principal; } @@ -809,16 +789,6 @@ namespace OpenIddict.Server }; await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The identity token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating identity token ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - return notification.Principal; } @@ -830,16 +800,6 @@ namespace OpenIddict.Server }; await _provider.DispatchAsync(notification); - - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The refresh token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating refresh tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - return notification.Principal; } } @@ -987,7 +947,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - if (context.Transaction.Properties.TryGetValue(Properties.Principal, out var principal)) + if (context.Transaction.Properties.TryGetValue(Properties.AmbientPrincipal, out var principal)) { context.Principal ??= (ClaimsPrincipal) principal; } diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs index 11cd8d94..9ece230a 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs @@ -31,12 +31,13 @@ namespace OpenIddict.Server HandleLogoutRequest.Descriptor, ApplyLogoutResponse.Descriptor, ApplyLogoutResponse.Descriptor, - ApplyLogoutResponse.Descriptor, + ApplyLogoutResponse.Descriptor, /* * Logout request validation: */ ValidatePostLogoutRedirectUriParameter.Descriptor, + ValidateIdTokenHint.Descriptor, ValidateClientPostLogoutRedirectUri.Descriptor, /* @@ -256,7 +257,7 @@ namespace OpenIddict.Server if (notification.IsLogoutAllowed) { - var @event = new ProcessSignoutResponseContext(context.Transaction) + var @event = new ProcessSignoutContext(context.Transaction) { Response = new OpenIddictResponse() }; @@ -402,6 +403,67 @@ namespace OpenIddict.Server } } + /// + /// Contains the logic responsible of rejecting logout requests that don't specify a valid id_token_hint. + /// + public class ValidateIdTokenHint : IOpenIddictServerHandler + { + private readonly IOpenIddictServerProvider _provider; + + public ValidateIdTokenHint([NotNull] IOpenIddictServerProvider provider) + => _provider = provider; + + /// + /// Gets the default descriptor definition assigned to this handler. + /// + public static OpenIddictServerHandlerDescriptor Descriptor { get; } + = OpenIddictServerHandlerDescriptor.CreateBuilder() + .UseScopedHandler() + .SetOrder(ValidatePostLogoutRedirectUriParameter.Descriptor.Order + 1_000) + .Build(); + + /// + /// Processes the event. + /// + /// The context associated with the event to process. + /// + /// A that can be used to monitor the asynchronous operation. + /// + public async ValueTask HandleAsync([NotNull] ValidateLogoutRequestContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (string.IsNullOrEmpty(context.Request.IdTokenHint)) + { + return; + } + + var notification = new DeserializeIdentityTokenContext(context.Transaction) + { + Token = context.Request.IdTokenHint + }; + + await _provider.DispatchAsync(notification); + + if (notification.Principal == null) + { + context.Reject( + error: Errors.InvalidRequest, + description: "The specified 'id_token_hint' parameter is invalid or malformed."); + + return; + } + + // Note: the expiration date associated with an identity token used as an id_token_hint is deliberately ignored. + + // Store the security principal extracted from the identity token as an environment property. + context.Transaction.Properties[Properties.AmbientPrincipal] = notification.Principal; + } + } + /// /// Contains the logic responsible of rejecting logout requests that use an invalid redirect_uri. /// Note: this handler is not used when the degraded mode is enabled. @@ -521,11 +583,11 @@ namespace OpenIddict.Server return default; } - // Note: at this stage, the validated redirect URI property may be null (e.g if an error - // is returned from the ExtractLogoutRequest/ValidateLogoutRequest events). - if (context.Transaction.Properties.TryGetValue(Properties.ValidatedPostLogoutRedirectUri, out var property)) + // Note: at this stage, the validated redirect URI property may be null (e.g if + // an error is returned from the ExtractLogoutRequest/ValidateLogoutRequest events). + if (context.Transaction.Properties.TryGetValue(Properties.ValidatedPostLogoutRedirectUri, out var address)) { - context.PostLogoutRedirectUri = (string) property; + context.PostLogoutRedirectUri = (string) address; } return default; diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs index aa74914a..cc1d1284 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs @@ -31,7 +31,7 @@ namespace OpenIddict.Server ExtractUserinfoRequest.Descriptor, ValidateUserinfoRequest.Descriptor, HandleUserinfoRequest.Descriptor, - ApplyUserinfoResponse.Descriptor, + ApplyUserinfoResponse.Descriptor, ApplyUserinfoResponse.Descriptor, ApplyUserinfoResponse.Descriptor, @@ -187,7 +187,7 @@ namespace OpenIddict.Server } // Store the security principal extracted from the authorization code/refresh token as an environment property. - context.Transaction.Properties[Properties.Principal] = notification.Principal; + context.Transaction.Properties[Properties.AmbientPrincipal] = notification.Principal; context.Logger.LogInformation("The userinfo request was successfully validated."); } @@ -432,15 +432,6 @@ namespace OpenIddict.Server await _provider.DispatchAsync(notification); - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The access token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of validating access tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - if (notification.Principal == null) { context.Logger.LogError("The userinfo request was rejected because the access token was invalid."); @@ -498,7 +489,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - if (context.Transaction.Properties.TryGetValue(Properties.Principal, out var principal)) + if (context.Transaction.Properties.TryGetValue(Properties.AmbientPrincipal, out var principal)) { context.Principal ??= (ClaimsPrincipal) principal; } diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.cs index f249d485..3114cde6 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Immutable; using System.ComponentModel; using System.Linq; +using System.Security.Claims; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; @@ -18,6 +19,7 @@ using OpenIddict.Abstractions; using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerHandlerFilters; +using Properties = OpenIddict.Server.OpenIddictServerConstants.Properties; namespace OpenIddict.Server { @@ -26,12 +28,17 @@ namespace OpenIddict.Server { public static ImmutableArray DefaultHandlers { get; } = ImmutableArray.Create( /* - * Challenge response processing: + * Authentication processing: + */ + AttachAmbientPrincipal.Descriptor, + + /* + * Challenge processing: */ AttachDefaultChallengeError.Descriptor, /* - * Sign-in response processing: + * Sign-in processing: */ ValidateSigninResponse.Descriptor, AttachDefaultScopes.Descriptor, @@ -50,16 +57,65 @@ namespace OpenIddict.Server .AddRange(Session.DefaultHandlers) .AddRange(Userinfo.DefaultHandlers); + /// + /// Contains the logic responsible of attaching the ambient principal resolved for the current request. + /// + public class AttachAmbientPrincipal : IOpenIddictServerHandler + { + /// + /// Gets the default descriptor definition assigned to this handler. + /// + public static OpenIddictServerHandlerDescriptor Descriptor { get; } + = OpenIddictServerHandlerDescriptor.CreateBuilder() + .UseSingletonHandler() + .SetOrder(int.MinValue + 100_000) + .Build(); + + /// + /// Processes the event. + /// + /// The context associated with the event to process. + /// + /// A that can be used to monitor the asynchronous operation. + /// + public ValueTask HandleAsync([NotNull] ProcessAuthenticationContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + switch (context.EndpointType) + { + case OpenIddictServerEndpointType.Authorization: + case OpenIddictServerEndpointType.Logout: + case OpenIddictServerEndpointType.Token when context.Request.IsAuthorizationCodeGrantType(): + case OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType(): + case OpenIddictServerEndpointType.Userinfo: + { + if (context.Transaction.Properties.TryGetValue(Properties.AmbientPrincipal, out var principal)) + { + context.Principal = (ClaimsPrincipal) principal; + } + + return default; + } + + default: throw new InvalidOperationException("An identity cannot be extracted from this request."); + } + } + } + /// /// Contains the logic responsible of ensuring that the challenge response contains an appropriate error. /// - public class AttachDefaultChallengeError : IOpenIddictServerHandler + public class AttachDefaultChallengeError : IOpenIddictServerHandler { /// /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } - = OpenIddictServerHandlerDescriptor.CreateBuilder() + = OpenIddictServerHandlerDescriptor.CreateBuilder() .UseSingletonHandler() .SetOrder(int.MinValue + 100_000) .Build(); @@ -71,7 +127,7 @@ namespace OpenIddict.Server /// /// A that can be used to monitor the asynchronous operation. /// - public ValueTask HandleAsync([NotNull] ProcessChallengeResponseContext context) + public ValueTask HandleAsync([NotNull] ProcessChallengeContext context) { if (context == null) { @@ -110,13 +166,13 @@ namespace OpenIddict.Server /// Contains the logic responsible of ensuring that the sign-in response /// is compatible with the type of the endpoint that handled the request. /// - public class ValidateSigninResponse : IOpenIddictServerHandler + public class ValidateSigninResponse : IOpenIddictServerHandler { /// /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } - = OpenIddictServerHandlerDescriptor.CreateBuilder() + = OpenIddictServerHandlerDescriptor.CreateBuilder() .UseSingletonHandler() .SetOrder(int.MinValue + 100_000) .Build(); @@ -128,7 +184,7 @@ namespace OpenIddict.Server /// /// A that can be used to monitor the asynchronous operation. /// - public ValueTask HandleAsync([NotNull] ProcessSigninResponseContext context) + public ValueTask HandleAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -167,13 +223,13 @@ namespace OpenIddict.Server /// /// Contains the logic responsible of attaching default scopes to the authentication principal. /// - public class AttachDefaultScopes : IOpenIddictServerHandler + public class AttachDefaultScopes : IOpenIddictServerHandler { /// /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } - = OpenIddictServerHandlerDescriptor.CreateBuilder() + = OpenIddictServerHandlerDescriptor.CreateBuilder() .UseSingletonHandler() .SetOrder(ValidateSigninResponse.Descriptor.Order + 1_000) .Build(); @@ -185,7 +241,7 @@ namespace OpenIddict.Server /// /// A that can be used to monitor the asynchronous operation. /// - public ValueTask HandleAsync([NotNull] ProcessSigninResponseContext context) + public ValueTask HandleAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -207,13 +263,13 @@ namespace OpenIddict.Server /// /// Contains the logic responsible of attaching default presenters to the authentication principal. /// - public class AttachDefaultPresenters : IOpenIddictServerHandler + public class AttachDefaultPresenters : IOpenIddictServerHandler { /// /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } - = OpenIddictServerHandlerDescriptor.CreateBuilder() + = OpenIddictServerHandlerDescriptor.CreateBuilder() .UseSingletonHandler() .SetOrder(AttachDefaultScopes.Descriptor.Order + 1_000) .Build(); @@ -225,7 +281,7 @@ namespace OpenIddict.Server /// /// A that can be used to monitor the asynchronous operation. /// - public ValueTask HandleAsync([NotNull] ProcessSigninResponseContext context) + public ValueTask HandleAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -246,13 +302,13 @@ namespace OpenIddict.Server /// /// Contains the logic responsible of selecting the token types returned to the client application. /// - public class EvaluateReturnedTokens : IOpenIddictServerHandler + public class EvaluateReturnedTokens : IOpenIddictServerHandler { /// /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } - = OpenIddictServerHandlerDescriptor.CreateBuilder() + = OpenIddictServerHandlerDescriptor.CreateBuilder() .UseSingletonHandler() .SetOrder(AttachDefaultPresenters.Descriptor.Order + 1_000) .Build(); @@ -264,7 +320,7 @@ namespace OpenIddict.Server /// /// A that can be used to monitor the asynchronous operation. /// - public ValueTask HandleAsync([NotNull] ProcessSigninResponseContext context) + public ValueTask HandleAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -332,7 +388,7 @@ namespace OpenIddict.Server /// /// Contains the logic responsible of generating and attaching an access token. /// - public class AttachAccessToken : IOpenIddictServerHandler + public class AttachAccessToken : IOpenIddictServerHandler { private readonly IOpenIddictServerProvider _provider; @@ -343,7 +399,7 @@ namespace OpenIddict.Server /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } - = OpenIddictServerHandlerDescriptor.CreateBuilder() + = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .UseScopedHandler() .SetOrder(EvaluateReturnedTokens.Descriptor.Order + 1_000) @@ -356,7 +412,7 @@ namespace OpenIddict.Server /// /// A that can be used to monitor the asynchronous operation. /// - public async ValueTask HandleAsync([NotNull] ProcessSigninResponseContext context) + public async ValueTask HandleAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -402,7 +458,7 @@ namespace OpenIddict.Server // Remove the destinations from the claim properties. foreach (var claim in principal.Claims) { - claim.Properties.Remove(Properties.Destinations); + claim.Properties.Remove(OpenIddictConstants.Properties.Destinations); } // When receiving a grant_type=refresh_token request, determine whether the client application @@ -427,15 +483,6 @@ namespace OpenIddict.Server await _provider.DispatchAsync(notification); - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The access token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of generating access tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - context.Response.TokenType = TokenTypes.Bearer; context.Response.AccessToken = notification.Token; @@ -458,7 +505,7 @@ namespace OpenIddict.Server /// /// Contains the logic responsible of generating and attaching an authorization code. /// - public class AttachAuthorizationCode : IOpenIddictServerHandler + public class AttachAuthorizationCode : IOpenIddictServerHandler { private readonly IOpenIddictServerProvider _provider; @@ -469,7 +516,7 @@ namespace OpenIddict.Server /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } - = OpenIddictServerHandlerDescriptor.CreateBuilder() + = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .UseScopedHandler() .SetOrder(AttachAccessToken.Descriptor.Order + 1_000) @@ -482,7 +529,7 @@ namespace OpenIddict.Server /// /// A that can be used to monitor the asynchronous operation. /// - public async ValueTask HandleAsync([NotNull] ProcessSigninResponseContext context) + public async ValueTask HandleAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -532,15 +579,6 @@ namespace OpenIddict.Server await _provider.DispatchAsync(notification); - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The authorization code was not correctly processed. This may indicate ") - .Append("that the event handler responsible of generating authorization codes ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - context.Response.Code = notification.Token; } } @@ -548,7 +586,7 @@ namespace OpenIddict.Server /// /// Contains the logic responsible of generating and attaching a refresh token. /// - public class AttachRefreshToken : IOpenIddictServerHandler + public class AttachRefreshToken : IOpenIddictServerHandler { private readonly IOpenIddictServerProvider _provider; @@ -559,7 +597,7 @@ namespace OpenIddict.Server /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } - = OpenIddictServerHandlerDescriptor.CreateBuilder() + = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .UseScopedHandler() .SetOrder(AttachAuthorizationCode.Descriptor.Order + 1_000) @@ -572,7 +610,7 @@ namespace OpenIddict.Server /// /// A that can be used to monitor the asynchronous operation. /// - public async ValueTask HandleAsync([NotNull] ProcessSigninResponseContext context) + public async ValueTask HandleAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -596,15 +634,6 @@ namespace OpenIddict.Server await _provider.DispatchAsync(notification); - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The refresh token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of generating refresh tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - context.Response.RefreshToken = notification.Token; } } @@ -612,7 +641,7 @@ namespace OpenIddict.Server /// /// Contains the logic responsible of generating and attaching an identity token. /// - public class AttachIdentityToken : IOpenIddictServerHandler + public class AttachIdentityToken : IOpenIddictServerHandler { private readonly IOpenIddictServerProvider _provider; @@ -623,7 +652,7 @@ namespace OpenIddict.Server /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } - = OpenIddictServerHandlerDescriptor.CreateBuilder() + = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .UseScopedHandler() .SetOrder(AttachRefreshToken.Descriptor.Order + 1_000) @@ -636,7 +665,7 @@ namespace OpenIddict.Server /// /// A that can be used to monitor the asynchronous operation. /// - public async ValueTask HandleAsync([NotNull] ProcessSigninResponseContext context) + public async ValueTask HandleAsync([NotNull] ProcessSigninContext context) { if (context == null) { @@ -677,7 +706,7 @@ namespace OpenIddict.Server // Remove the destinations from the claim properties. foreach (var claim in principal.Claims) { - claim.Properties.Remove(Properties.Destinations); + claim.Properties.Remove(OpenIddictConstants.Properties.Destinations); } var lifetime = context.Principal.GetIdentityTokenLifetime() ?? context.Options.IdentityTokenLifetime; @@ -750,15 +779,6 @@ namespace OpenIddict.Server await _provider.DispatchAsync(notification); - if (!notification.IsHandled) - { - throw new InvalidOperationException(new StringBuilder() - .Append("The identity token was not correctly processed. This may indicate ") - .Append("that the event handler responsible of generating identity tokens ") - .Append("was not registered or was explicitly removed from the handlers list.") - .ToString()); - } - context.Response.IdToken = notification.Token; static HashAlgorithm GetHashAlgorithm(SigningCredentials credentials)