From 7af133f98c4f43aa35e2f0be930862366b42154e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Mon, 15 Jan 2024 09:13:54 +0100 Subject: [PATCH] Introduce a new DisableUserinfo option in RefreshTokenAuthenticationRequest to allow refreshing tokens acquired during a client credentials flow --- .../OpenIddictClientEvents.cs | 5 +++++ .../OpenIddictClientHandlers.cs | 8 ++++---- .../OpenIddictClientModels.cs | 19 +++++++++++++++++-- .../OpenIddictClientService.cs | 6 ++++++ 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/OpenIddict.Client/OpenIddictClientEvents.cs b/src/OpenIddict.Client/OpenIddictClientEvents.cs index 508ed4ce..b209025f 100644 --- a/src/OpenIddict.Client/OpenIddictClientEvents.cs +++ b/src/OpenIddict.Client/OpenIddictClientEvents.cs @@ -859,6 +859,11 @@ public static partial class OpenIddictClientEvents /// public bool DisableFrontchannelIdentityTokenNonceValidation { get; set; } + /// + /// Gets or sets a boolean indicating whether userinfo retrieval should be disabled. + /// + public bool DisableUserinfoRetrieval { get; set; } + /// /// Gets or sets a boolean indicating whether userinfo validation should be disabled. /// diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.cs index 1ebecd94..cc0df1b7 100644 --- a/src/OpenIddict.Client/OpenIddictClientHandlers.cs +++ b/src/OpenIddict.Client/OpenIddictClientHandlers.cs @@ -2262,7 +2262,7 @@ public static partial class OpenIddictClientHandlers // For client credentials, device authorization, resource owner password // credentials and refresh token requests, always send a token request. GrantTypes.ClientCredentials or GrantTypes.DeviceCode or - GrantTypes.Password or GrantTypes.RefreshToken => true, + GrantTypes.Password or GrantTypes.RefreshToken => true, _ => false }; @@ -3557,8 +3557,8 @@ public static partial class OpenIddictClientHandlers // // Note: the userinfo endpoint is an optional endpoint and may not be supported. GrantTypes.AuthorizationCode or GrantTypes.Implicit or - GrantTypes.DeviceCode or GrantTypes.Password or GrantTypes.RefreshToken - when context.UserinfoEndpoint is not null && + GrantTypes.DeviceCode or GrantTypes.Password or GrantTypes.RefreshToken + when !context.DisableUserinfoRetrieval && context.UserinfoEndpoint is not null && (!string.IsNullOrEmpty(context.BackchannelAccessToken) || !string.IsNullOrEmpty(context.FrontchannelAccessToken)) => true, @@ -3721,7 +3721,7 @@ public static partial class OpenIddictClientHandlers context.RejectUserinfoToken) = context.GrantType switch { GrantTypes.AuthorizationCode or GrantTypes.Implicit or - GrantTypes.DeviceCode or GrantTypes.Password or GrantTypes.RefreshToken + GrantTypes.DeviceCode or GrantTypes.Password or GrantTypes.RefreshToken when context.SendUserinfoRequest => (true, false, true, true), _ => (false, false, false, false) diff --git a/src/OpenIddict.Client/OpenIddictClientModels.cs b/src/OpenIddict.Client/OpenIddictClientModels.cs index 09c1e852..15dab957 100644 --- a/src/OpenIddict.Client/OpenIddictClientModels.cs +++ b/src/OpenIddict.Client/OpenIddictClientModels.cs @@ -283,8 +283,7 @@ public static class OpenIddictClientModels /// /// /// Note: in most cases, an empty principal will be returned, unless the authorization server - /// supports returning a non-standard identity token for the client credentials grant or - /// allows sending userinfo requests with an access token representing a client application. + /// supports returning a non-standard identity token for the client credentials grant. /// public required ClaimsPrincipal Principal { get; init; } @@ -342,6 +341,11 @@ public static class OpenIddictClientModels /// public required string DeviceCode { get; init; } + /// + /// Gets or sets a boolean indicating whether userinfo should be disabled. + /// + public bool DisableUserinfo { get; set; } + /// /// Gets or sets the maximum duration during which token requests will be sent /// (typically, the same value as the "expires_in" parameter returned by the @@ -561,6 +565,11 @@ public static class OpenIddictClientModels /// public CancellationToken CancellationToken { get; init; } + /// + /// Gets or sets a boolean indicating whether userinfo should be disabled. + /// + public bool DisableUserinfo { get; set; } + /// /// Gets or sets the password that will be sent to the authorization server. /// @@ -680,6 +689,12 @@ public static class OpenIddictClientModels /// public CancellationToken CancellationToken { get; init; } + /// + /// Gets or sets a boolean indicating whether userinfo should be disabled, which may be required + /// when sending a refresh token that was acquired using a user-less flow (e.g client credentials). + /// + public bool DisableUserinfo { get; set; } + /// /// Gets or sets the application-specific properties that will be added to the context. /// diff --git a/src/OpenIddict.Client/OpenIddictClientService.cs b/src/OpenIddict.Client/OpenIddictClientService.cs index 2ffdfb18..b5113f34 100644 --- a/src/OpenIddict.Client/OpenIddictClientService.cs +++ b/src/OpenIddict.Client/OpenIddictClientService.cs @@ -571,6 +571,8 @@ public class OpenIddictClientService { CancellationToken = source.Token, DeviceCode = request.DeviceCode, + DisableUserinfoRetrieval = request.DisableUserinfo, + DisableUserinfoValidation = request.DisableUserinfo, GrantType = GrantTypes.DeviceCode, Issuer = request.Issuer, ProviderName = request.ProviderName, @@ -773,6 +775,8 @@ public class OpenIddictClientService var context = new ProcessAuthenticationContext(transaction) { CancellationToken = request.CancellationToken, + DisableUserinfoRetrieval = request.DisableUserinfo, + DisableUserinfoValidation = request.DisableUserinfo, GrantType = GrantTypes.Password, Issuer = request.Issuer, Password = request.Password, @@ -868,6 +872,8 @@ public class OpenIddictClientService var context = new ProcessAuthenticationContext(transaction) { CancellationToken = request.CancellationToken, + DisableUserinfoRetrieval = request.DisableUserinfo, + DisableUserinfoValidation = request.DisableUserinfo, GrantType = GrantTypes.RefreshToken, Issuer = request.Issuer, ProviderName = request.ProviderName,