diff --git a/src/OpenIddict.Abstractions/OpenIddictConstants.cs b/src/OpenIddict.Abstractions/OpenIddictConstants.cs index b2ef4250..4a7c9cf4 100644 --- a/src/OpenIddict.Abstractions/OpenIddictConstants.cs +++ b/src/OpenIddict.Abstractions/OpenIddictConstants.cs @@ -133,6 +133,7 @@ public static class OpenIddictConstants public const string Issuer = "oi_iss"; public const string Nonce = "oi_nce"; public const string PostLogoutRedirectUri = "oi_pstlgt_reduri"; + public const string ProviderName = "oi_prvd_name"; public const string Presenter = "oi_prst"; public const string RedirectUri = "oi_reduri"; public const string RefreshTokenLifetime = "oi_reft_lft"; diff --git a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs index f6f365c7..882b6be4 100644 --- a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs +++ b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs @@ -165,7 +165,8 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler registration.Issuer == issuer) ?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0292)); + // If an explicit provider name was also added, ensure the two values point to the same issuer. + var provider = context.StateTokenPrincipal.GetClaim(Claims.Private.ProviderName); + if (!string.IsNullOrEmpty(provider) && + !string.IsNullOrEmpty(context.Registration.ProviderName) && + !string.Equals(provider, context.Registration.ProviderName, StringComparison.Ordinal)) + { + throw new InvalidOperationException(SR.GetResourceString(SR.ID0349)); + } + // Resolve and attach the server configuration to the context. context.Configuration = await context.Registration.ConfigurationManager.GetConfigurationAsync(default) ?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0140)); @@ -951,7 +960,7 @@ public static partial class OpenIddictClientHandlers // If the two values don't match, this may indicate a mix-up attack attempt. if (!Uri.TryCreate(issuer, UriKind.Absolute, out Uri? uri) || - !uri.IsWellFormedOriginalString() || uri != context.Configuration.Issuer) + !uri.IsWellFormedOriginalString() || uri != context.Issuer) { context.Reject( error: Errors.InvalidRequest, @@ -4548,7 +4557,8 @@ public static partial class OpenIddictClientHandlers // // See https://datatracker.ietf.org/doc/html/draft-bradley-oauth-jwt-encoded-state-09 // for more information about this special claim. - principal.SetClaim(Claims.AuthorizationServer, context.Issuer.AbsoluteUri); + principal.SetClaim(Claims.AuthorizationServer, context.Issuer.AbsoluteUri) + .SetClaim(Claims.Private.ProviderName, context.Registration.ProviderName); // Store the request forgery protection in the state token so it can be later used to // ensure the authorization response sent to the redirection endpoint is not forged. @@ -5123,7 +5133,8 @@ public static partial class OpenIddictClientHandlers // // See https://datatracker.ietf.org/doc/html/draft-bradley-oauth-jwt-encoded-state-09 // for more information about this special claim. - principal.SetClaim(Claims.AuthorizationServer, context.Issuer.AbsoluteUri); + principal.SetClaim(Claims.AuthorizationServer, context.Issuer.AbsoluteUri) + .SetClaim(Claims.Private.ProviderName, context.Registration.ProviderName); // Store the request forgery protection in the state token so it can be later used to // ensure the logout response sent to the post-logout redirection endpoint is not forged.