From 2b333272bf5050a243a6f89c09985f7cbfeeb2d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Fri, 14 Oct 2022 17:38:28 +0200 Subject: [PATCH] Update the client stack to normalize authorization error responses --- .../OpenIddictResources.resx | 51 ++++++++++++-- .../OpenIddictClientSystemNetHttpHandlers.cs | 8 +-- .../OpenIddictClientHandlers.Userinfo.cs | 2 +- .../OpenIddictClientHandlers.cs | 67 +++++++++++++++---- ...enIddictValidationSystemNetHttpHandlers.cs | 8 +-- 5 files changed, 109 insertions(+), 27 deletions(-) diff --git a/src/OpenIddict.Abstractions/OpenIddictResources.resx b/src/OpenIddict.Abstractions/OpenIddictResources.resx index 61147ea0..fe6a6565 100644 --- a/src/OpenIddict.Abstractions/OpenIddictResources.resx +++ b/src/OpenIddict.Abstractions/OpenIddictResources.resx @@ -1280,12 +1280,6 @@ Alternatively, you can disable the token storage feature by calling 'services.Ad Error description: {1} Error URI: {2} - - A generic error was returned by the remote authorization server. - - - An unsupported response was returned by the remote authorization server. - The provider name cannot be null or empty. @@ -1790,6 +1784,48 @@ Alternatively, you can disable the token storage feature by calling 'services.Ad The userinfo request was rejected by the remote server. + + The authorization demand was denied by the user or by the identity provider. + + + The authorization request was rejected due to a missing or invalid parameter. + + + The authorization request was rejected due to an invalid scope. + + + The authorization request was rejected due to a remote server error. + + + The authorization request was rejected due to a transient error. + + + The authorization request was rejected due to the use of an incorrect or unauthorized grant type. + + + The authorization request was rejected due to an unsupported response type. + + + The authorization request was rejected because the user didn't select a user account. + + + The authorization request was rejected because user consent was required to proceed the request. + + + The authorization request was rejected because user interaction was required to proceed the request. + + + The authorization request was rejected because user (re-)authentication was required to proceed the request. + + + The authorization request was rejected by the identity provider. + + + A generic {StatusCode} error was returned by the remote authorization server. + + + An unsupported response was returned by the remote authorization server. + The '{0}' parameter shouldn't be null or empty at this point. @@ -2422,6 +2458,9 @@ This may indicate that the hashed entry is corrupted or malformed. The userinfo request was rejected by the remote authorization server: {Response}. + + The authorization request was rejected by the remote authorization server: {Response}. + https://documentation.openiddict.com/errors/{0} diff --git a/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs b/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs index d3f10dfd..6dc5c3bc 100644 --- a/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs +++ b/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs @@ -749,8 +749,8 @@ public static partial class OpenIddictClientSystemNetHttpHandlers 503 => Errors.TemporarilyUnavailable, _ => Errors.ServerError }, - description: SR.GetResourceString(SR.ID0328), - uri: SR.FormatID8000(SR.ID0328)); + description: SR.FormatID2161((int) response.StatusCode), + uri: SR.FormatID8000(SR.ID2161)); return; } @@ -764,8 +764,8 @@ public static partial class OpenIddictClientSystemNetHttpHandlers context.Reject( error: Errors.ServerError, - description: SR.GetResourceString(SR.ID0329), - uri: SR.FormatID8000(SR.ID0329)); + description: SR.GetResourceString(SR.ID2162), + uri: SR.FormatID8000(SR.ID2162)); return; } diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.Userinfo.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.Userinfo.cs index 766c6f56..bae995a9 100644 --- a/src/OpenIddict.Client/OpenIddictClientHandlers.Userinfo.cs +++ b/src/OpenIddict.Client/OpenIddictClientHandlers.Userinfo.cs @@ -121,7 +121,7 @@ public static partial class OpenIddictClientHandlers error: context.Response.Error switch { Errors.InsufficientScope => Errors.InsufficientScope, - Errors.InvalidRequest => Errors.InvalidToken, + Errors.InvalidRequest => Errors.InvalidRequest, Errors.InvalidToken => Errors.InvalidToken, _ => Errors.ServerError }, diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.cs index a1b6d3a0..1cb688f2 100644 --- a/src/OpenIddict.Client/OpenIddictClientHandlers.cs +++ b/src/OpenIddict.Client/OpenIddictClientHandlers.cs @@ -36,7 +36,7 @@ public static partial class OpenIddictClientHandlers ValidateStateTokenEndpointType.Descriptor, ResolveClientRegistrationFromStateToken.Descriptor, ValidateIssuerParameter.Descriptor, - ValidateFrontchannelErrorParameters.Descriptor, + HandleFrontchannelErrorResponse.Descriptor, ResolveGrantTypeFromStateToken.Descriptor, ResolveResponseTypeFromStateToken.Descriptor, @@ -663,7 +663,7 @@ public static partial class OpenIddictClientHandlers /// /// Contains the logic responsible for rejecting errored authorization responses. /// - public class ValidateFrontchannelErrorParameters : IOpenIddictClientHandler + public class HandleFrontchannelErrorResponse : IOpenIddictClientHandler { /// /// Gets the default descriptor definition assigned to this handler. @@ -671,7 +671,7 @@ public static partial class OpenIddictClientHandlers public static OpenIddictClientHandlerDescriptor Descriptor { get; } = OpenIddictClientHandlerDescriptor.CreateBuilder() .AddFilter() - .UseSingletonHandler() + .UseSingletonHandler() .SetOrder(ValidateIssuerParameter.Descriptor.Order + 1_000) .Build(); @@ -683,17 +683,60 @@ public static partial class OpenIddictClientHandlers throw new ArgumentNullException(nameof(context)); } - var (error, description, uri) = ( - (string?) context.Request[Parameters.Error], - (string?) context.Request[Parameters.ErrorDescription], - (string?) context.Request[Parameters.ErrorUri]); - + // Note: for more information about the standard error codes, + // see https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1 and + // https://openid.net/specs/openid-connect-core-1_0.html#AuthError. + var error = (string?) context.Request[Parameters.Error]; if (!string.IsNullOrEmpty(error)) { + context.Logger.LogInformation(SR.GetResourceString(SR.ID6208), context.Request); + context.Reject( - error: error ?? Errors.InvalidRequest, - description: description, - uri: uri); + error: error switch + { + Errors.AccessDenied => Errors.AccessDenied, + Errors.AccountSelectionRequired => Errors.AccountSelectionRequired, + Errors.ConsentRequired => Errors.ConsentRequired, + Errors.InteractionRequired => Errors.InteractionRequired, + Errors.InvalidRequest => Errors.InvalidRequest, + Errors.InvalidScope => Errors.InvalidScope, + Errors.LoginRequired => Errors.LoginRequired, + Errors.ServerError => Errors.ServerError, + Errors.TemporarilyUnavailable => Errors.TemporarilyUnavailable, + Errors.UnauthorizedClient => Errors.UnauthorizedClient, + Errors.UnsupportedResponseType => Errors.UnsupportedResponseType, + _ => Errors.InvalidRequest + }, + description: error switch + { + Errors.AccessDenied => SR.GetResourceString(SR.ID2149), + Errors.AccountSelectionRequired => SR.GetResourceString(SR.ID2156), + Errors.ConsentRequired => SR.GetResourceString(SR.ID2157), + Errors.InteractionRequired => SR.GetResourceString(SR.ID2158), + Errors.InvalidRequest => SR.GetResourceString(SR.ID2150), + Errors.InvalidScope => SR.GetResourceString(SR.ID2151), + Errors.LoginRequired => SR.GetResourceString(SR.ID2159), + Errors.ServerError => SR.GetResourceString(SR.ID2152), + Errors.TemporarilyUnavailable => SR.GetResourceString(SR.ID2153), + Errors.UnauthorizedClient => SR.GetResourceString(SR.ID2154), + Errors.UnsupportedResponseType => SR.GetResourceString(SR.ID2155), + _ => SR.GetResourceString(SR.ID2160) + }, + uri: error switch + { + Errors.AccessDenied => SR.FormatID8000(SR.ID2149), + Errors.AccountSelectionRequired => SR.FormatID8000(SR.ID2156), + Errors.ConsentRequired => SR.FormatID8000(SR.ID2157), + Errors.InteractionRequired => SR.FormatID8000(SR.ID2158), + Errors.InvalidRequest => SR.FormatID8000(SR.ID2150), + Errors.InvalidScope => SR.FormatID8000(SR.ID2151), + Errors.LoginRequired => SR.FormatID8000(SR.ID2159), + Errors.ServerError => SR.FormatID8000(SR.ID2152), + Errors.TemporarilyUnavailable => SR.FormatID8000(SR.ID2153), + Errors.UnauthorizedClient => SR.FormatID8000(SR.ID2154), + Errors.UnsupportedResponseType => SR.FormatID8000(SR.ID2155), + _ => SR.FormatID8000(SR.ID2160) + }); return default; } @@ -716,7 +759,7 @@ public static partial class OpenIddictClientHandlers .AddFilter() .AddFilter() .UseSingletonHandler() - .SetOrder(ValidateFrontchannelErrorParameters.Descriptor.Order + 1_000) + .SetOrder(HandleFrontchannelErrorResponse.Descriptor.Order + 1_000) .SetType(OpenIddictClientHandlerType.BuiltIn) .Build(); diff --git a/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs b/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs index ab38845e..f017716b 100644 --- a/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs +++ b/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs @@ -750,8 +750,8 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers 503 => Errors.TemporarilyUnavailable, _ => Errors.ServerError }, - description: SR.GetResourceString(SR.ID0328), - uri: SR.FormatID8000(SR.ID0328)); + description: SR.FormatID2161((int) response.StatusCode), + uri: SR.FormatID8000(SR.ID2161)); return; } @@ -765,8 +765,8 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers context.Reject( error: Errors.ServerError, - description: SR.GetResourceString(SR.ID0329), - uri: SR.FormatID8000(SR.ID0329)); + description: SR.GetResourceString(SR.ID2162), + uri: SR.FormatID8000(SR.ID2162)); return; }