From e9eff303ef497a927f892180ed757634fa8ea2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Tue, 23 Jan 2024 13:29:13 +0100 Subject: [PATCH] Update MapStandardWebServicesFederationClaims to fall back to "name" when no "preferred_username" claim was found --- .../Controllers/AuthenticationController.cs | 17 +++++----------- .../Controllers/AuthenticationController.cs | 15 ++++---------- .../Controllers/AuthorizationController.cs | 5 ++++- .../Controllers/AuthenticationController.cs | 20 ++++++++----------- .../Controllers/AuthenticationController.cs | 18 +++++++---------- .../Controllers/AuthorizationController.cs | 7 ++++++- .../OpenIddictClientHandlers.cs | 3 ++- 7 files changed, 36 insertions(+), 49 deletions(-) diff --git a/sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/AuthenticationController.cs b/sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/AuthenticationController.cs index 0eab91b4..4ffcb7ab 100644 --- a/sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/AuthenticationController.cs +++ b/sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/AuthenticationController.cs @@ -187,21 +187,14 @@ namespace OpenIddict.Sandbox.AspNet.Client.Controllers // Build the authentication properties based on the properties that were added when the challenge was triggered. var properties = new AuthenticationProperties(result.Properties.Dictionary - .Where(item => item switch - { + .Where(item => item.Key is // Preserve the return URL. - { Key: ".redirect" } => true, + ".redirect" or // If needed, the tokens returned by the authorization server can be stored in the authentication cookie. - { - Key: OpenIddictClientOwinConstants.Tokens.BackchannelAccessToken or - OpenIddictClientOwinConstants.Tokens.BackchannelIdentityToken or - OpenIddictClientOwinConstants.Tokens.RefreshToken - } => true, - - // Don't add the other properties to the external cookie. - _ => false - }) + OpenIddictClientOwinConstants.Tokens.BackchannelAccessToken or + OpenIddictClientOwinConstants.Tokens.BackchannelIdentityToken or + OpenIddictClientOwinConstants.Tokens.RefreshToken) .ToDictionary(pair => pair.Key, pair => pair.Value)); context.Authentication.SignIn(properties, identity); diff --git a/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthenticationController.cs b/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthenticationController.cs index ce5bf496..fc2b0e6c 100644 --- a/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthenticationController.cs +++ b/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthenticationController.cs @@ -79,20 +79,13 @@ namespace OpenIddict.Sandbox.AspNet.Server.Controllers // Build the authentication properties based on the properties that were added when the challenge was triggered. var properties = new AuthenticationProperties(result.Properties.Dictionary - .Where(item => item switch - { + .Where(item => item.Key is // Preserve the return URL. - { Key: ".redirect" } => true, + ".redirect" or // If needed, the tokens returned by the authorization server can be stored in the authentication cookie. - { - Key: OpenIddictClientOwinConstants.Tokens.BackchannelAccessToken or - OpenIddictClientOwinConstants.Tokens.RefreshToken - } => true, - - // Don't add the other properties to the external cookie. - _ => false - }) + OpenIddictClientOwinConstants.Tokens.BackchannelAccessToken or + OpenIddictClientOwinConstants.Tokens.RefreshToken) .ToDictionary(pair => pair.Key, pair => pair.Value)); context.Authentication.SignIn(properties, identity); diff --git a/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthorizationController.cs b/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthorizationController.cs index 274faf01..9c1bf961 100644 --- a/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthorizationController.cs +++ b/sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthorizationController.cs @@ -150,6 +150,7 @@ namespace OpenIddict.Sandbox.AspNet.Server.Controllers identity.SetClaim(Claims.Subject, user.Id) .SetClaim(Claims.Email, user.Email) .SetClaim(Claims.Name, user.UserName) + .SetClaim(Claims.PreferredUsername, user.UserName) .SetClaims(Claims.Role, (await context.Get().GetRolesAsync(user.Id)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope @@ -268,6 +269,7 @@ namespace OpenIddict.Sandbox.AspNet.Server.Controllers identity.SetClaim(Claims.Subject, user.Id) .SetClaim(Claims.Email, user.Email) .SetClaim(Claims.Name, user.UserName) + .SetClaim(Claims.PreferredUsername, user.UserName) .SetClaims(Claims.Role, (await context.Get().GetRolesAsync(user.Id)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope @@ -387,6 +389,7 @@ namespace OpenIddict.Sandbox.AspNet.Server.Controllers identity.SetClaim(Claims.Subject, user.Id) .SetClaim(Claims.Email, user.Email) .SetClaim(Claims.Name, user.UserName) + .SetClaim(Claims.PreferredUsername, user.UserName) .SetClaims(Claims.Role, (await context.Get().GetRolesAsync(user.Id)).ToImmutableArray()); identity.SetDestinations(GetDestinations); @@ -408,7 +411,7 @@ namespace OpenIddict.Sandbox.AspNet.Server.Controllers switch (claim.Type) { - case Claims.Name: + case Claims.Name or Claims.PreferredUsername: yield return Destinations.AccessToken; if (claim.Subject.HasScope(Scopes.Profile)) diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/AuthenticationController.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/AuthenticationController.cs index 1ba37311..18c274be 100644 --- a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/AuthenticationController.cs +++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/AuthenticationController.cs @@ -160,7 +160,10 @@ public class AuthenticationController : Controller } // Build an identity based on the external claims and that will be used to create the authentication cookie. - var identity = new ClaimsIdentity(authenticationType: "ExternalLogin"); + var identity = new ClaimsIdentity( + authenticationType: "ExternalLogin", + nameType: ClaimTypes.Name, + roleType: ClaimTypes.Role); // By default, OpenIddict will automatically try to map the email/name and name identifier claims from // their standard OpenID Connect or provider-specific equivalent, if available. If needed, additional @@ -182,18 +185,11 @@ public class AuthenticationController : Controller // If needed, the tokens returned by the authorization server can be stored in the authentication cookie. // // To make cookies less heavy, tokens that are not used are filtered out before creating the cookie. - properties.StoreTokens(result.Properties.GetTokens().Where(token => token switch - { + properties.StoreTokens(result.Properties.GetTokens().Where(token => token.Name is // Preserve the access, identity and refresh tokens returned in the token response, if available. - { - Name: OpenIddictClientAspNetCoreConstants.Tokens.BackchannelAccessToken or - OpenIddictClientAspNetCoreConstants.Tokens.BackchannelIdentityToken or - OpenIddictClientAspNetCoreConstants.Tokens.RefreshToken - } => true, - - // Ignore the other tokens. - _ => false - })); + OpenIddictClientAspNetCoreConstants.Tokens.BackchannelAccessToken or + OpenIddictClientAspNetCoreConstants.Tokens.BackchannelIdentityToken or + OpenIddictClientAspNetCoreConstants.Tokens.RefreshToken)); // Ask the default sign-in handler to return a new cookie and redirect the // user agent to the return URL stored in the authentication properties. diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthenticationController.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthenticationController.cs index 13997f63..668fab03 100644 --- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthenticationController.cs +++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthenticationController.cs @@ -51,7 +51,10 @@ public class AuthenticationController : Controller } // Build an identity based on the external claims and that will be used to create the authentication cookie. - var identity = new ClaimsIdentity(authenticationType: "ExternalLogin"); + var identity = new ClaimsIdentity( + authenticationType: "ExternalLogin", + nameType: ClaimTypes.Name, + roleType: ClaimTypes.Role); // By default, OpenIddict will automatically try to map the email/name and name identifier claims from // their standard OpenID Connect or provider-specific equivalent, if available. If needed, additional @@ -72,17 +75,10 @@ public class AuthenticationController : Controller // If needed, the tokens returned by the authorization server can be stored in the authentication cookie. // To make cookies less heavy, tokens that are not used are filtered out before creating the cookie. - properties.StoreTokens(result.Properties.GetTokens().Where(token => token switch - { + properties.StoreTokens(result.Properties.GetTokens().Where(token => token.Name is // Preserve the access and refresh tokens returned in the token response, if available. - { - Name: OpenIddictClientAspNetCoreConstants.Tokens.BackchannelAccessToken or - OpenIddictClientAspNetCoreConstants.Tokens.RefreshToken - } => true, - - // Ignore the other tokens. - _ => false - })); + OpenIddictClientAspNetCoreConstants.Tokens.BackchannelAccessToken or + OpenIddictClientAspNetCoreConstants.Tokens.RefreshToken)); // Ask the default sign-in handler to return a new cookie and redirect the // user agent to the return URL stored in the authentication properties. diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthorizationController.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthorizationController.cs index 6c43cfce..5244617e 100644 --- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthorizationController.cs +++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthorizationController.cs @@ -184,6 +184,7 @@ public class AuthorizationController : Controller identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user)) .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) + .SetClaim(Claims.PreferredUsername, await _userManager.GetUserNameAsync(user)) .SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope @@ -277,6 +278,7 @@ public class AuthorizationController : Controller identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user)) .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) + .SetClaim(Claims.PreferredUsername, await _userManager.GetUserNameAsync(user)) .SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope @@ -371,6 +373,7 @@ public class AuthorizationController : Controller identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user)) .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) + .SetClaim(Claims.PreferredUsername, await _userManager.GetUserNameAsync(user)) .SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope @@ -485,6 +488,7 @@ public class AuthorizationController : Controller identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user)) .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) + .SetClaim(Claims.PreferredUsername, await _userManager.GetUserNameAsync(user)) .SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); // Note: in this sample, the granted scopes match the requested scope @@ -538,6 +542,7 @@ public class AuthorizationController : Controller identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user)) .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user)) .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user)) + .SetClaim(Claims.PreferredUsername, await _userManager.GetUserNameAsync(user)) .SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray()); identity.SetDestinations(GetDestinations); @@ -558,7 +563,7 @@ public class AuthorizationController : Controller switch (claim.Type) { - case Claims.Name: + case Claims.Name or Claims.PreferredUsername: yield return Destinations.AccessToken; if (claim.Subject.HasScope(Scopes.Profile)) diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.cs index 4174cc69..2ffd34d0 100644 --- a/src/OpenIddict.Client/OpenIddictClientHandlers.cs +++ b/src/OpenIddict.Client/OpenIddictClientHandlers.cs @@ -4091,7 +4091,8 @@ public static partial class OpenIddictClientHandlers .SetClaim(ClaimTypes.Email, context.MergedPrincipal.GetClaim(Claims.Email), issuer) .SetClaim(ClaimTypes.Gender, context.MergedPrincipal.GetClaim(Claims.Gender), issuer) .SetClaim(ClaimTypes.GivenName, context.MergedPrincipal.GetClaim(Claims.GivenName), issuer) - .SetClaim(ClaimTypes.Name, context.MergedPrincipal.GetClaim(Claims.PreferredUsername), issuer) + .SetClaim(ClaimTypes.Name, context.MergedPrincipal.GetClaim(Claims.PreferredUsername) ?? + context.MergedPrincipal.GetClaim(Claims.Name), issuer) .SetClaim(ClaimTypes.NameIdentifier, context.MergedPrincipal.GetClaim(Claims.Subject), issuer) .SetClaim(ClaimTypes.OtherPhone, context.MergedPrincipal.GetClaim(Claims.PhoneNumber), issuer) .SetClaim(ClaimTypes.Surname, context.MergedPrincipal.GetClaim(Claims.FamilyName), issuer);