From aa734f1e10f8a88f42a65d84364e0ddd5710277c Mon Sep 17 00:00:00 2001 From: tempcode Date: Mon, 20 May 2024 10:12:53 +0200 Subject: [PATCH 01/30] feat(Users): added default services to retrieve user to link to login data feat(Users): changed account controller code to use new services feat(Users): load all services in reversed enum to ret last registered services feat(Users): updated view code resolve #16026 --- .../Controllers/AccountController.cs | 25 ++++++----- .../DefaultExternalLoginUserToRelateFinder.cs | 42 +++++++++++++++++++ .../Views/Account/LinkExternalLogin.cshtml | 6 +-- .../IExternalLoginUserToRelateFinder.cs | 14 +++++++ 4 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs create mode 100644 src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 221e2402247..c89a90e6ef8 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -19,6 +19,7 @@ using OrchardCore.Modules; using OrchardCore.Mvc.Core.Utilities; using OrchardCore.Settings; +using OrchardCore.Users.Abstractions; using OrchardCore.Users.Events; using OrchardCore.Users.Handlers; using OrchardCore.Users.Models; @@ -47,6 +48,7 @@ public class AccountController : AccountBaseController private readonly IClock _clock; private readonly IDistributedCache _distributedCache; private readonly IEnumerable _externalLoginHandlers; + private readonly IEnumerable _externalLoginUsrFinder; protected readonly IHtmlLocalizer H; protected readonly IStringLocalizer S; @@ -67,7 +69,8 @@ public AccountController( IShellFeaturesManager shellFeaturesManager, IDisplayManager loginFormDisplayManager, IUpdateModelAccessor updateModelAccessor, - IEnumerable externalLoginHandlers) + IEnumerable externalLoginHandlers, + IEnumerable externalLoginUsrFinder) { _signInManager = signInManager; _userManager = userManager; @@ -83,6 +86,7 @@ public AccountController( _loginFormDisplayManager = loginFormDisplayManager; _updateModelAccessor = updateModelAccessor; _externalLoginHandlers = externalLoginHandlers; + _externalLoginUsrFinder = externalLoginUsrFinder.Reverse(); H = htmlLocalizer; S = stringLocalizer; @@ -384,12 +388,9 @@ public async Task ExternalLoginCallback(string returnUrl = null, } else { - var email = info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); - - if (!string.IsNullOrWhiteSpace(email)) - { - iUser = await _userManager.FindByEmailAsync(email); - } + //really important the order of the services registration in the dependency injection context + var usrFinder = _externalLoginUsrFinder.Where(x => x.CanManageThis(info.LoginProvider)).FirstOrDefault(); + iUser = await usrFinder?.FindUserToRelateAsync(info) ?? null; ViewData["ReturnUrl"] = returnUrl; ViewData["LoginProvider"] = info.LoginProvider; @@ -409,7 +410,7 @@ public async Task ExternalLoginCallback(string returnUrl = null, // Link external login to an existing user ViewData["UserName"] = iUser.UserName; - ViewData["Email"] = email; + ViewData["LinkParameterValue"] = usrFinder?.GetValueThatLinkAccount(info); return View(nameof(LinkExternalLogin)); } @@ -423,6 +424,8 @@ public async Task ExternalLoginCallback(string returnUrl = null, } else { + var email = info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); + var externalLoginViewModel = new RegisterExternalLoginViewModel { NoPassword = registrationSettings.NoPasswordForExternalUsers, @@ -630,9 +633,9 @@ public async Task LinkExternalLogin(LinkExternalLoginViewModel mo return NotFound(); } - var email = info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); - - var user = await _userManager.FindByEmailAsync(email); + //really important the order of the services registration in the dependency injection context + var usrFinder = _externalLoginUsrFinder.Where(x => x.CanManageThis(info.LoginProvider)).FirstOrDefault(); + var user = await usrFinder?.FindUserToRelateAsync(info) ?? null; if (user == null) { diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs b/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs new file mode 100644 index 00000000000..7584510c3a6 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs @@ -0,0 +1,42 @@ + +using System.Runtime.CompilerServices; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using OrchardCore.Users.Abstractions; + +namespace OrchardCore.Users.Services; + +public class DefaultExternalLoginUserToRelateFinder : IExternalLoginUserToRelateFinder +{ + private readonly UserManager _userManager; + + public DefaultExternalLoginUserToRelateFinder(UserManager userManager) + { + _userManager = userManager; + } + + public bool CanManageThis(string extLoginKind) + { + return true; + } + + public async Task FindUserToRelateAsync(ExternalLoginInfo info) + { + //the default behavior previously used in OrchardCore + var email = info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); + + IUser iUser = null; + if (!string.IsNullOrWhiteSpace(email)) + { + iUser = await _userManager.FindByEmailAsync(email); + } + + return iUser; + } + + public string GetValueThatLinkAccount(ExternalLoginInfo info) + { + return info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); + } +} \ No newline at end of file diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml index 383f70374f2..2e94dbef77a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml @@ -7,7 +7,7 @@

@T["Link your account."]

- @T["You've successfully authenticated with {0}. You already have an account with this email address. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"]] + @T["You've successfully authenticated with {0}. Seems already exist an account identificable by this information: {1}. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"], ViewData["LinkParameterData"]]


@@ -20,9 +20,9 @@
- +
- +
diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs new file mode 100644 index 00000000000..5bae5050866 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs @@ -0,0 +1,14 @@ + +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; + +namespace OrchardCore.Users.Abstractions; + +public interface IExternalLoginUserToRelateFinder +{ + bool CanManageThis(string extLoginKind); + + Task FindUserToRelateAsync(ExternalLoginInfo info); + + string GetValueThatLinkAccount(ExternalLoginInfo info); +} \ No newline at end of file From 2ee51cddb1e78fd96895a9224aaf037b77c3d578 Mon Sep 17 00:00:00 2001 From: tempcode Date: Wed, 22 May 2024 16:42:04 +0200 Subject: [PATCH 02/30] fix: avoid null excpetion in AccountController fix: fixed LinkParameterValue name in ViewData fix: added to DI context DefaultExternalLoginUserToRelateFinder --- .../OrchardCore.Users/Controllers/AccountController.cs | 2 +- src/OrchardCore.Modules/OrchardCore.Users/Startup.cs | 3 +++ .../Views/Account/LinkExternalLogin.cshtml | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index c89a90e6ef8..0a94954b419 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -390,7 +390,7 @@ public async Task ExternalLoginCallback(string returnUrl = null, { //really important the order of the services registration in the dependency injection context var usrFinder = _externalLoginUsrFinder.Where(x => x.CanManageThis(info.LoginProvider)).FirstOrDefault(); - iUser = await usrFinder?.FindUserToRelateAsync(info) ?? null; + iUser = usrFinder == null ? null : await usrFinder.FindUserToRelateAsync(info); ViewData["ReturnUrl"] = returnUrl; ViewData["LoginProvider"] = info.LoginProvider; diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs index 466bc4db375..565b4a3360d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs @@ -39,6 +39,7 @@ using OrchardCore.Settings.Deployment; using OrchardCore.Setup.Events; using OrchardCore.Sms; +using OrchardCore.Users.Abstractions; using OrchardCore.Users.Commands; using OrchardCore.Users.Controllers; using OrchardCore.Users.Deployment; @@ -198,6 +199,8 @@ public override void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddRecipeExecutionStep(); services.AddScoped, LoginFormDisplayDriver>(); + + services.AddScoped(); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml index 2e94dbef77a..eab93349699 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml @@ -7,7 +7,7 @@

@T["Link your account."]

- @T["You've successfully authenticated with {0}. Seems already exist an account identificable by this information: {1}. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"], ViewData["LinkParameterData"]] + @T["You've successfully authenticated with {0}. Seems already exist an account identificable by this information: {1}. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"], ViewData["LinkParameterValue"]]


@@ -20,9 +20,9 @@
- +
- +
From bd014736f523154e0622a6d6e66e2ebbd7bc685a Mon Sep 17 00:00:00 2001 From: tempcode Date: Mon, 10 Jun 2024 12:22:49 +0200 Subject: [PATCH 03/30] style: name changes, docs, indent, new line style: formatting comment and code style: added last extra line style: change var name to usrLocator docs: reviewd comment --- .../Controllers/AccountController.cs | 22 ++++---- .../DefaultExternalLoginUserToRelateFinder.cs | 56 +++++++++---------- .../Views/Account/LinkExternalLogin.cshtml | 2 +- .../IExternalLoginUserToRelateFinder.cs | 9 ++- 4 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index f6ae927f331..3d4acc0f44a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -53,7 +53,7 @@ public class AccountController : AccountBaseController private readonly IClock _clock; private readonly IDistributedCache _distributedCache; private readonly IEnumerable _externalLoginHandlers; - private readonly IEnumerable _externalLoginUsrFinder; + private readonly IEnumerable _externalLoginUserLocator; private static readonly JsonMergeSettings _jsonMergeSettings = new() { @@ -81,7 +81,7 @@ public AccountController( IDisplayManager loginFormDisplayManager, IUpdateModelAccessor updateModelAccessor, IEnumerable externalLoginHandlers, - IEnumerable externalLoginUsrFinder) + IEnumerable externalLoginUserLocator) { _signInManager = signInManager; _userManager = userManager; @@ -97,7 +97,9 @@ public AccountController( _loginFormDisplayManager = loginFormDisplayManager; _updateModelAccessor = updateModelAccessor; _externalLoginHandlers = externalLoginHandlers; - _externalLoginUsrFinder = externalLoginUsrFinder.Reverse(); + // reverse services loaded from DI context to select before last services registered + // really important the order of the services registration in the dependency injection context + _externalLoginUserLocator = externalLoginUserLocator.Reverse(); H = htmlLocalizer; S = stringLocalizer; @@ -320,7 +322,7 @@ private async Task ExternalLoginSignInAsync(IUser user, ExternalLo var userInfo = user as User; var context = new UpdateUserContext(user, info.LoginProvider, externalClaims, userInfo.Properties) - { + { UserClaims = userInfo.UserClaims, UserRoles = userRoles, }; @@ -406,9 +408,8 @@ public async Task ExternalLoginCallback(string returnUrl = null, } else { - //really important the order of the services registration in the dependency injection context - var usrFinder = _externalLoginUsrFinder.Where(x => x.CanManageThis(info.LoginProvider)).FirstOrDefault(); - iUser = usrFinder == null ? null : await usrFinder.FindUserToRelateAsync(info); + var userLocator = _externalLoginUserLocator.Where(x => x.CanHandle(info)).FirstOrDefault(); + iUser = userLocator == null ? null : await userLocator.GetUserAsync(info); ViewData["ReturnUrl"] = returnUrl; ViewData["LoginProvider"] = info.LoginProvider; @@ -428,7 +429,7 @@ public async Task ExternalLoginCallback(string returnUrl = null, // Link external login to an existing user ViewData["UserName"] = iUser.UserName; - ViewData["LinkParameterValue"] = usrFinder?.GetValueThatLinkAccount(info); + ViewData["LinkParameterValue"] = userLocator?.GetValueThatLinkAccount(info); return View(nameof(LinkExternalLogin)); } @@ -651,9 +652,8 @@ public async Task LinkExternalLogin(LinkExternalLoginViewModel mo return NotFound(); } - //really important the order of the services registration in the dependency injection context - var usrFinder = _externalLoginUsrFinder.Where(x => x.CanManageThis(info.LoginProvider)).FirstOrDefault(); - var user = await usrFinder?.FindUserToRelateAsync(info) ?? null; + var userLocator = _externalLoginUserLocator.Where(x => x.CanHandle(info)).FirstOrDefault(); + var user = await userLocator?.GetUserAsync(info) ?? null; if (user == null) { diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs b/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs index 7584510c3a6..7b5f9c4fc21 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs @@ -1,5 +1,3 @@ - -using System.Runtime.CompilerServices; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; @@ -9,34 +7,34 @@ namespace OrchardCore.Users.Services; public class DefaultExternalLoginUserToRelateFinder : IExternalLoginUserToRelateFinder { - private readonly UserManager _userManager; - - public DefaultExternalLoginUserToRelateFinder(UserManager userManager) - { - _userManager = userManager; - } - - public bool CanManageThis(string extLoginKind) - { - return true; - } - - public async Task FindUserToRelateAsync(ExternalLoginInfo info) - { - //the default behavior previously used in OrchardCore - var email = info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); - - IUser iUser = null; - if (!string.IsNullOrWhiteSpace(email)) + private readonly UserManager _userManager; + + public DefaultExternalLoginUserToRelateFinder(UserManager userManager) + { + _userManager = userManager; + } + + public bool CanHandle(ExternalLoginInfo info) { - iUser = await _userManager.FindByEmailAsync(email); + return true; } - return iUser; - } + public async Task GetUserAsync(ExternalLoginInfo info) + { + // the default behavior previously used in OrchardCore + var email = info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); - public string GetValueThatLinkAccount(ExternalLoginInfo info) - { - return info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); - } -} \ No newline at end of file + IUser iUser = null; + if (!string.IsNullOrWhiteSpace(email)) + { + iUser = await _userManager.FindByEmailAsync(email); + } + + return iUser; + } + + public string GetValueThatLinkAccount(ExternalLoginInfo info) + { + return info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml index eab93349699..eb554b299cf 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml @@ -7,7 +7,7 @@

@T["Link your account."]

- @T["You've successfully authenticated with {0}. Seems already exist an account identificable by this information: {1}. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"], ViewData["LinkParameterValue"]] + @T["You've successfully authenticated with {0}. Seems already exist an account related to: {1}. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"], ViewData["LinkParameterValue"]]


diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs index 5bae5050866..6ea8b8032d2 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs @@ -1,4 +1,3 @@ - using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; @@ -6,9 +5,9 @@ namespace OrchardCore.Users.Abstractions; public interface IExternalLoginUserToRelateFinder { - bool CanManageThis(string extLoginKind); + bool CanHandle(ExternalLoginInfo info); - Task FindUserToRelateAsync(ExternalLoginInfo info); + Task GetUserAsync(ExternalLoginInfo info); - string GetValueThatLinkAccount(ExternalLoginInfo info); -} \ No newline at end of file + string GetValueThatLinkAccount(ExternalLoginInfo info); +} From ed96f408c822c8074caede18da172996190d20d9 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 10 Jun 2024 09:06:46 -0700 Subject: [PATCH 04/30] cleanup before comments --- .../Controllers/AccountController.cs | 24 ++++++++++++------- .../DefaultExternalLoginUserToRelateFinder.cs | 18 +++++--------- .../OrchardCore.Users/Startup.cs | 3 --- .../Views/Account/LinkExternalLogin.cshtml | 2 +- .../IExternalLoginUserToRelateFinder.cs | 2 +- .../Extensions/ExternalLoginInfoExtensions.cs | 10 ++++++++ .../UsersServiceCollectionExtensions.cs | 2 ++ 7 files changed, 35 insertions(+), 26 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Users.Core/Extensions/ExternalLoginInfoExtensions.cs diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 3d4acc0f44a..da296ef486e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -97,8 +97,7 @@ public AccountController( _loginFormDisplayManager = loginFormDisplayManager; _updateModelAccessor = updateModelAccessor; _externalLoginHandlers = externalLoginHandlers; - // reverse services loaded from DI context to select before last services registered - // really important the order of the services registration in the dependency injection context + // Reverse the order of services to prioritize external services first, placing them before the default implementation. _externalLoginUserLocator = externalLoginUserLocator.Reverse(); H = htmlLocalizer; @@ -302,7 +301,6 @@ public async Task ChangePassword(ChangePasswordViewModel model, s public IActionResult ChangePasswordConfirmation() => View(); - [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] @@ -409,7 +407,9 @@ public async Task ExternalLoginCallback(string returnUrl = null, else { var userLocator = _externalLoginUserLocator.Where(x => x.CanHandle(info)).FirstOrDefault(); - iUser = userLocator == null ? null : await userLocator.GetUserAsync(info); + if (userLocator != null) { + iUser = await userLocator.GetUserAsync(info); + } ViewData["ReturnUrl"] = returnUrl; ViewData["LoginProvider"] = info.LoginProvider; @@ -429,7 +429,14 @@ public async Task ExternalLoginCallback(string returnUrl = null, // Link external login to an existing user ViewData["UserName"] = iUser.UserName; - ViewData["LinkParameterValue"] = userLocator?.GetValueThatLinkAccount(info); + if (userLocator != null) + { + ViewData["LinkParameterValue"] = userLocator.GetValueThatLinkAccount(info); + } + else + { + ViewData["LinkParameterValue"] = info.GetEmail(); + } return View(nameof(LinkExternalLogin)); } @@ -443,8 +450,6 @@ public async Task ExternalLoginCallback(string returnUrl = null, } else { - var email = info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); - var externalLoginViewModel = new RegisterExternalLoginViewModel { NoPassword = registrationSettings.NoPasswordForExternalUsers, @@ -453,7 +458,7 @@ public async Task ExternalLoginCallback(string returnUrl = null, // If registrationSettings.NoUsernameForExternalUsers is true, this username will not be used UserName = await GenerateUsernameAsync(info), - Email = email + Email = info.GetEmail(), }; // The user doesn't exist and no information required, we can create the account locally @@ -652,8 +657,9 @@ public async Task LinkExternalLogin(LinkExternalLoginViewModel mo return NotFound(); } + var userLocator = _externalLoginUserLocator.Where(x => x.CanHandle(info)).FirstOrDefault(); - var user = await userLocator?.GetUserAsync(info) ?? null; + var user = await userLocator?.GetUserAsync(info); if (user == null) { diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs b/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs index 7b5f9c4fc21..2436d1242e4 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs @@ -15,26 +15,20 @@ public DefaultExternalLoginUserToRelateFinder(UserManager userManager) } public bool CanHandle(ExternalLoginInfo info) - { - return true; - } - + => true; + public async Task GetUserAsync(ExternalLoginInfo info) { - // the default behavior previously used in OrchardCore - var email = info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); + var email = info.GetEmail(); - IUser iUser = null; if (!string.IsNullOrWhiteSpace(email)) { - iUser = await _userManager.FindByEmailAsync(email); + return await _userManager.FindByEmailAsync(email); } - return iUser; + return null; } public string GetValueThatLinkAccount(ExternalLoginInfo info) - { - return info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); - } + => info.GetEmail(); } diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs index 975bf7af57b..d2a1af4de9e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs @@ -39,7 +39,6 @@ using OrchardCore.Settings.Deployment; using OrchardCore.Setup.Events; using OrchardCore.Sms; -using OrchardCore.Users.Abstractions; using OrchardCore.Users.Commands; using OrchardCore.Users.Controllers; using OrchardCore.Users.Deployment; @@ -248,8 +247,6 @@ public override void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddRecipeExecutionStep(); services.AddScoped, LoginFormDisplayDriver>(); - - services.AddScoped(); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml index eb554b299cf..85590fcf088 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml @@ -7,7 +7,7 @@

@T["Link your account."]

- @T["You've successfully authenticated with {0}. Seems already exist an account related to: {1}. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"], ViewData["LinkParameterValue"]] + @T["You've successfully authenticated with {0}. You already have an account assosiated with {1}. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"], ViewData["LinkParameterValue"]]


diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs index 6ea8b8032d2..cfb30c2d7c2 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; -namespace OrchardCore.Users.Abstractions; +namespace OrchardCore.Users; public interface IExternalLoginUserToRelateFinder { diff --git a/src/OrchardCore/OrchardCore.Users.Core/Extensions/ExternalLoginInfoExtensions.cs b/src/OrchardCore/OrchardCore.Users.Core/Extensions/ExternalLoginInfoExtensions.cs new file mode 100644 index 00000000000..c7417ec3c2f --- /dev/null +++ b/src/OrchardCore/OrchardCore.Users.Core/Extensions/ExternalLoginInfoExtensions.cs @@ -0,0 +1,10 @@ +using System.Security.Claims; + +namespace Microsoft.AspNetCore.Identity; + +public static class ExternalLoginInfoExtensions +{ + public static string GetEmail(this ExternalLoginInfo info) + => info.Principal.FindFirstValue(ClaimTypes.Email) + ?? info.Principal.FindFirstValue("email"); +} diff --git a/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs index 4d071924f84..e473f1204a9 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs @@ -38,6 +38,8 @@ public static IServiceCollection AddUsers(this IServiceCollection services) services.TryAddScoped>(sp => sp.GetRequiredService()); services.TryAddScoped>(sp => sp.GetRequiredService()); services.TryAddScoped>(sp => sp.GetRequiredService()); + + services.AddScoped(); services.AddScoped(); services.TryAddScoped>(sp => sp.GetRequiredService()); From 6d74eaf13eca9d2df1ba88c076db3658a8ea2f12 Mon Sep 17 00:00:00 2001 From: tempcode Date: Mon, 10 Jun 2024 18:19:16 +0200 Subject: [PATCH 05/30] style: from LinkParameterValue to ExternalUserIdentifier Update src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml Co-authored-by: Mike Alhayek --- .../OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml index 85590fcf088..dde9d53ce5f 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml @@ -22,7 +22,7 @@
- +
From 30188bfa48538dc1534899b7becf48a4c27212d1 Mon Sep 17 00:00:00 2001 From: tempcode Date: Mon, 10 Jun 2024 18:19:38 +0200 Subject: [PATCH 06/30] style: from LinkParameterValue to ExternalUserIdentifier Update src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml Co-authored-by: Mike Alhayek --- .../OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml index dde9d53ce5f..bfcd2f9f95d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml @@ -20,7 +20,7 @@
- +
From ed52a4c265b6d8d242572abfed6e4e643730a171 Mon Sep 17 00:00:00 2001 From: tempcode Date: Mon, 10 Jun 2024 18:19:59 +0200 Subject: [PATCH 07/30] style: from LinkParameterValue to ExternalUserIdentifier Update src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml Co-authored-by: Mike Alhayek --- .../OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml index bfcd2f9f95d..426c065ab4b 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml @@ -7,7 +7,7 @@

@T["Link your account."]

- @T["You've successfully authenticated with {0}. You already have an account assosiated with {1}. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"], ViewData["LinkParameterValue"]] + @T["You've successfully authenticated with {0}. You already have an account associated with {1}. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"], ViewData["ExternalUserIdentifier"]]


From 472665263f2380f70c1adb5bd7176afd2a6e6d87 Mon Sep 17 00:00:00 2001 From: tempcode Date: Mon, 10 Jun 2024 19:17:05 +0200 Subject: [PATCH 08/30] style: rename method, comment interface fix: build by move service to OrchardCore.Users.Core style: rename interface to IUserToExternalLoginProvider style: rename method to GetIdentifierKey style: rename service class to DefaultUserToExternalLoginProvider style: rename ViewData object to ExternalUserIdentifier --- .../Controllers/AccountController.cs | 13 +++-- .../IExternalLoginUserToRelateFinder.cs | 13 ----- .../Services/IUserToExternalLoginProvider.cs | 51 +++++++++++++++++++ .../UsersServiceCollectionExtensions.cs | 4 +- .../DefaultUserToExternalLoginProvider.cs} | 10 ++-- 5 files changed, 63 insertions(+), 28 deletions(-) delete mode 100644 src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs create mode 100644 src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs rename src/{OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs => OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs} (65%) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index da296ef486e..6e99182b262 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -24,7 +24,6 @@ using OrchardCore.Modules; using OrchardCore.Mvc.Core.Utilities; using OrchardCore.Settings; -using OrchardCore.Users.Abstractions; using OrchardCore.Users.Events; using OrchardCore.Users.Handlers; using OrchardCore.Users.Models; @@ -53,7 +52,7 @@ public class AccountController : AccountBaseController private readonly IClock _clock; private readonly IDistributedCache _distributedCache; private readonly IEnumerable _externalLoginHandlers; - private readonly IEnumerable _externalLoginUserLocator; + private readonly IEnumerable _externalLoginUserLocator; private static readonly JsonMergeSettings _jsonMergeSettings = new() { @@ -81,7 +80,7 @@ public AccountController( IDisplayManager loginFormDisplayManager, IUpdateModelAccessor updateModelAccessor, IEnumerable externalLoginHandlers, - IEnumerable externalLoginUserLocator) + IEnumerable externalLoginUserLocator) { _signInManager = signInManager; _userManager = userManager; @@ -431,11 +430,11 @@ public async Task ExternalLoginCallback(string returnUrl = null, ViewData["UserName"] = iUser.UserName; if (userLocator != null) { - ViewData["LinkParameterValue"] = userLocator.GetValueThatLinkAccount(info); - } - else + ViewData["ExternalUserIdentifier"] = userLocator.GetIdentifierKey(info); + } + else { - ViewData["LinkParameterValue"] = info.GetEmail(); + ViewData["ExternalUserIdentifier"] = info.GetEmail(); } return View(nameof(LinkExternalLogin)); diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs deleted file mode 100644 index cfb30c2d7c2..00000000000 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginUserToRelateFinder.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity; - -namespace OrchardCore.Users; - -public interface IExternalLoginUserToRelateFinder -{ - bool CanHandle(ExternalLoginInfo info); - - Task GetUserAsync(ExternalLoginInfo info); - - string GetValueThatLinkAccount(ExternalLoginInfo info); -} diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs new file mode 100644 index 00000000000..7ec1fecd171 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs @@ -0,0 +1,51 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; + +namespace OrchardCore.Users; + +/// +/// Interface IUserToExternalLoginProvider allow to create services used to decide +/// when link an existing local user account to the login informations that comes from an external +/// login system like OpenId or GitHub. +/// +public interface IUserToExternalLoginProvider +{ + /// + /// Method CanHandle extabilish if the service that implement this interface can handle + /// a kind of external login. + /// + /// + /// external login information with type and other data to extabilish if + /// service can hadle this kind of external login. + /// + /// + /// True, if the service can handle the external login by the informations in the parameter. False, instead. + /// + bool CanHandle(ExternalLoginInfo info); + + /// + /// Method GetUserAsync return a local user account that match an identifier used by the + /// service to return an existing local user account. + /// + /// + /// external login information to extabilish if + /// exist a local user account that match login data. + /// + /// + /// an object that implement IUser, if the exit a local account that match the external login data. Null, instead. + /// + Task GetUserAsync(ExternalLoginInfo info); + + /// + /// Method GetIdentifierKey return the value of the login data used by the service to + /// match a local user account to the external login informations. + /// + /// + /// external login information. + /// + /// + /// a string that is used like an identifier to match an existing local user account. + /// Used in the related views to render the value that cause the page display. + /// + string GetIdentifierKey(ExternalLoginInfo info); +} diff --git a/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs index e473f1204a9..da747cc9cd1 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs @@ -38,8 +38,8 @@ public static IServiceCollection AddUsers(this IServiceCollection services) services.TryAddScoped>(sp => sp.GetRequiredService()); services.TryAddScoped>(sp => sp.GetRequiredService()); services.TryAddScoped>(sp => sp.GetRequiredService()); - - services.AddScoped(); + + services.AddScoped(); services.AddScoped(); services.TryAddScoped>(sp => sp.GetRequiredService()); diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs b/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs similarity index 65% rename from src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs rename to src/OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs index 2436d1242e4..a59e70968f2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Services/DefaultExternalLoginUserToRelateFinder.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs @@ -1,22 +1,20 @@ -using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; -using OrchardCore.Users.Abstractions; namespace OrchardCore.Users.Services; -public class DefaultExternalLoginUserToRelateFinder : IExternalLoginUserToRelateFinder +public class DefaultUserToExternalLoginProvider : IUserToExternalLoginProvider { private readonly UserManager _userManager; - public DefaultExternalLoginUserToRelateFinder(UserManager userManager) + public DefaultUserToExternalLoginProvider(UserManager userManager) { _userManager = userManager; } public bool CanHandle(ExternalLoginInfo info) => true; - + public async Task GetUserAsync(ExternalLoginInfo info) { var email = info.GetEmail(); @@ -29,6 +27,6 @@ public async Task GetUserAsync(ExternalLoginInfo info) return null; } - public string GetValueThatLinkAccount(ExternalLoginInfo info) + public string GetIdentifierKey(ExternalLoginInfo info) => info.GetEmail(); } From c8898a42f6d94cc5e54f079fa52c1543bb169deb Mon Sep 17 00:00:00 2001 From: tempcode Date: Mon, 10 Jun 2024 19:27:33 +0200 Subject: [PATCH 09/30] style: improved comments --- .../Services/IUserToExternalLoginProvider.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs index 7ec1fecd171..1d6d98a8ea8 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs @@ -16,7 +16,7 @@ public interface IUserToExternalLoginProvider /// /// /// external login information with type and other data to extabilish if - /// service can hadle this kind of external login. + /// service can handle this kind of external login. /// /// /// True, if the service can handle the external login by the informations in the parameter. False, instead. @@ -24,15 +24,13 @@ public interface IUserToExternalLoginProvider bool CanHandle(ExternalLoginInfo info); /// - /// Method GetUserAsync return a local user account that match an identifier used by the - /// service to return an existing local user account. + /// Method GetUserAsync return a local user account that match the login data in the parameter. /// /// - /// external login information to extabilish if - /// exist a local user account that match login data. + /// external login information, used to establish if exists a local user account that match login data. /// /// - /// an object that implement IUser, if the exit a local account that match the external login data. Null, instead. + /// an object that implement IUser, if the exist a local account that match the external login data. Null, instead. /// Task GetUserAsync(ExternalLoginInfo info); @@ -41,7 +39,7 @@ public interface IUserToExternalLoginProvider /// match a local user account to the external login informations. /// /// - /// external login information. + /// external login informations. /// /// /// a string that is used like an identifier to match an existing local user account. From e04b9aa0ddde5ef0bd3499104e4b647920d404d0 Mon Sep 17 00:00:00 2001 From: tempcode Date: Mon, 10 Jun 2024 19:30:47 +0200 Subject: [PATCH 10/30] style: removed grammar errors in comments --- .../Services/IUserToExternalLoginProvider.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs index 1d6d98a8ea8..10d749a6794 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs @@ -11,11 +11,11 @@ namespace OrchardCore.Users; public interface IUserToExternalLoginProvider { /// - /// Method CanHandle extabilish if the service that implement this interface can handle - /// a kind of external login. + /// Method CanHandle establish if the service that implement this interface can handle + /// this kind of external login. /// /// - /// external login information with type and other data to extabilish if + /// external login information with type and other data to establish if /// service can handle this kind of external login. /// /// From 1ce666591f5fc934184c031de8a2cf25dc5adcb7 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 10 Jun 2024 11:44:42 -0700 Subject: [PATCH 11/30] Update src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml --- .../OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml index 426c065ab4b..0722ebc4d58 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml @@ -20,7 +20,7 @@
- +
From 5115dd330c2ddd4627839a628ce10cab0eb3a6f5 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 10 Jun 2024 11:44:58 -0700 Subject: [PATCH 12/30] Update src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs --- .../Services/IUserToExternalLoginProvider.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs index 10d749a6794..144877cd77c 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs @@ -4,9 +4,7 @@ namespace OrchardCore.Users; /// -/// Interface IUserToExternalLoginProvider allow to create services used to decide -/// when link an existing local user account to the login informations that comes from an external -/// login system like OpenId or GitHub. +/// Provides a methods to link a local user with an externally authenticated user during registration. /// public interface IUserToExternalLoginProvider { From 604fd3500ce5d60b019edf41aac6703e34f794ea Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 10 Jun 2024 11:45:10 -0700 Subject: [PATCH 13/30] Update src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs --- .../Services/IUserToExternalLoginProvider.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs index 144877cd77c..049cde85bc8 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs @@ -9,15 +9,11 @@ namespace OrchardCore.Users; public interface IUserToExternalLoginProvider { /// - /// Method CanHandle establish if the service that implement this interface can handle - /// this kind of external login. + /// Checks of the implement can handle the given external login information. /// - /// - /// external login information with type and other data to establish if - /// service can handle this kind of external login. - /// + /// The external login information. /// - /// True, if the service can handle the external login by the informations in the parameter. False, instead. + /// True if the service can handle the given external login information. False otherwise. /// bool CanHandle(ExternalLoginInfo info); From 81791828c3bf9d5d96ca76ae60c1d228cd26e48f Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 10 Jun 2024 11:45:19 -0700 Subject: [PATCH 14/30] Update src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs --- .../Services/IUserToExternalLoginProvider.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs index 049cde85bc8..17ebc389d33 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs @@ -18,13 +18,12 @@ public interface IUserToExternalLoginProvider bool CanHandle(ExternalLoginInfo info); /// - /// Method GetUserAsync return a local user account that match the login data in the parameter. + /// + /// Retrieves a local user account that corresponds to the provided external login information, if one exists. /// - /// - /// external login information, used to establish if exists a local user account that match login data. - /// + /// The external login information. /// - /// an object that implement IUser, if the exist a local account that match the external login data. Null, instead. + /// An instance of if there's a local account matching the external login data; otherwise, null. /// Task GetUserAsync(ExternalLoginInfo info); From f210886753640c0ebe207a07054b9782a4f2d53f Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 10 Jun 2024 11:45:27 -0700 Subject: [PATCH 15/30] Update src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs --- .../Services/IUserToExternalLoginProvider.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs index 17ebc389d33..9f44a521a4b 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs @@ -28,15 +28,10 @@ public interface IUserToExternalLoginProvider Task GetUserAsync(ExternalLoginInfo info); /// - /// Method GetIdentifierKey return the value of the login data used by the service to - /// match a local user account to the external login informations. + /// Gets the identifier's key used by the implementation. /// /// - /// external login informations. - /// - /// - /// a string that is used like an identifier to match an existing local user account. - /// Used in the related views to render the value that cause the page display. - /// + /// The external login information. + /// A string identifier denoting the property name utilized for user identification. string GetIdentifierKey(ExternalLoginInfo info); } From 31967eda55f0d175aab7c79e0891bf9806311791 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 10 Jun 2024 11:48:13 -0700 Subject: [PATCH 16/30] cleanup --- .../OrchardCore.Users/Controllers/AccountController.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 6e99182b262..57f79d7c731 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -52,7 +52,7 @@ public class AccountController : AccountBaseController private readonly IClock _clock; private readonly IDistributedCache _distributedCache; private readonly IEnumerable _externalLoginHandlers; - private readonly IEnumerable _externalLoginUserLocator; + private readonly IEnumerable _userToExternalLoginProviders; private static readonly JsonMergeSettings _jsonMergeSettings = new() { @@ -80,7 +80,7 @@ public AccountController( IDisplayManager loginFormDisplayManager, IUpdateModelAccessor updateModelAccessor, IEnumerable externalLoginHandlers, - IEnumerable externalLoginUserLocator) + IEnumerable userToExternalLoginProviders) { _signInManager = signInManager; _userManager = userManager; @@ -97,7 +97,7 @@ public AccountController( _updateModelAccessor = updateModelAccessor; _externalLoginHandlers = externalLoginHandlers; // Reverse the order of services to prioritize external services first, placing them before the default implementation. - _externalLoginUserLocator = externalLoginUserLocator.Reverse(); + _userToExternalLoginProviders = userToExternalLoginProviders.Reverse(); H = htmlLocalizer; S = stringLocalizer; @@ -405,7 +405,7 @@ public async Task ExternalLoginCallback(string returnUrl = null, } else { - var userLocator = _externalLoginUserLocator.Where(x => x.CanHandle(info)).FirstOrDefault(); + var userLocator = _externalLoginUserLocator.FirstOrDefault(x => x.CanHandle(info)); if (userLocator != null) { iUser = await userLocator.GetUserAsync(info); } @@ -657,7 +657,7 @@ public async Task LinkExternalLogin(LinkExternalLoginViewModel mo return NotFound(); } - var userLocator = _externalLoginUserLocator.Where(x => x.CanHandle(info)).FirstOrDefault(); + var userLocator = _userToExternalLoginProviders.FirstOrDefault(x => x.CanHandle(info)); var user = await userLocator?.GetUserAsync(info); if (user == null) From 010de021f2557eab4be33c07e24abd4a4bfaec9a Mon Sep 17 00:00:00 2001 From: tempcode Date: Tue, 11 Jun 2024 09:08:08 +0200 Subject: [PATCH 17/30] fix: var name in account controller --- .../OrchardCore.Users/Controllers/AccountController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 57f79d7c731..1d0d6096822 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -405,7 +405,7 @@ public async Task ExternalLoginCallback(string returnUrl = null, } else { - var userLocator = _externalLoginUserLocator.FirstOrDefault(x => x.CanHandle(info)); + var userLocator = _userToExternalLoginProviders.FirstOrDefault(x => x.CanHandle(info)); if (userLocator != null) { iUser = await userLocator.GetUserAsync(info); } From c9914fe6fb29b734114358140cdb4286c0c7ffed Mon Sep 17 00:00:00 2001 From: tempcode Date: Tue, 11 Jun 2024 09:13:29 +0200 Subject: [PATCH 18/30] fix: comments in IUserToExternaLoginProvider --- .../Services/IUserToExternalLoginProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs index 9f44a521a4b..05b97792251 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs @@ -17,7 +17,6 @@ public interface IUserToExternalLoginProvider /// bool CanHandle(ExternalLoginInfo info); - /// /// /// Retrieves a local user account that corresponds to the provided external login information, if one exists. /// @@ -30,7 +29,6 @@ public interface IUserToExternalLoginProvider /// /// Gets the identifier's key used by the implementation. /// - /// /// The external login information. /// A string identifier denoting the property name utilized for user identification. string GetIdentifierKey(ExternalLoginInfo info); From 12e05970af277756ff1bfb2f97e9dadbd7cacca4 Mon Sep 17 00:00:00 2001 From: tempcode Date: Wed, 12 Jun 2024 08:51:40 +0200 Subject: [PATCH 19/30] updated comment in IUserToExternalLoginProvider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Services/IUserToExternalLoginProvider.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs index 05b97792251..d5279010714 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs @@ -9,11 +9,11 @@ namespace OrchardCore.Users; public interface IUserToExternalLoginProvider { /// - /// Checks of the implement can handle the given external login information. + /// Checks if the implementation can handle the given external login information. /// /// The external login information. /// - /// True if the service can handle the given external login information. False otherwise. + /// if the service can handle the given external login information, otherwise. /// bool CanHandle(ExternalLoginInfo info); @@ -22,7 +22,7 @@ public interface IUserToExternalLoginProvider /// /// The external login information. /// - /// An instance of if there's a local account matching the external login data; otherwise, null. + /// An instance of if there's a local account matching the external login data; otherwise, . /// Task GetUserAsync(ExternalLoginInfo info); From 3255f3d591c0cd461d60aba0ecad677b3c4df5b5 Mon Sep 17 00:00:00 2001 From: tempcode Date: Wed, 12 Jun 2024 08:53:47 +0200 Subject: [PATCH 20/30] simplified code in DefaultUserToExternalLoginProvider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Services/DefaultUserToExternalLoginProvider.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs index a59e70968f2..223644a005e 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs @@ -19,12 +19,7 @@ public async Task GetUserAsync(ExternalLoginInfo info) { var email = info.GetEmail(); - if (!string.IsNullOrWhiteSpace(email)) - { - return await _userManager.FindByEmailAsync(email); - } - - return null; + return !string.IsNullOrWhiteSpace(email) ? await _userManager.FindByEmailAsync(email) : null; } public string GetIdentifierKey(ExternalLoginInfo info) From a330c508e23ffbb5b951f8aa388e40a68ad2cac1 Mon Sep 17 00:00:00 2001 From: tempcode Date: Wed, 12 Jun 2024 08:58:56 +0200 Subject: [PATCH 21/30] updated class comment IUserToExternalLoginProvider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Services/IUserToExternalLoginProvider.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs index d5279010714..6d9c9810493 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs @@ -4,8 +4,13 @@ namespace OrchardCore.Users; /// -/// Provides a methods to link a local user with an externally authenticated user during registration. +/// Service to link a local user with an externally authenticated user during registration. /// +/// +/// +/// Implement this interface if you want to provide an alternative way to link a local user with an external login provider. +/// +/// public interface IUserToExternalLoginProvider { /// From 7e50a95783ae21a6676188350c5157a3b56d2b29 Mon Sep 17 00:00:00 2001 From: tempcode Date: Wed, 12 Jun 2024 08:59:42 +0200 Subject: [PATCH 22/30] style: code to new line in ExternalLoginInfoExtensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Extensions/ExternalLoginInfoExtensions.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Users.Core/Extensions/ExternalLoginInfoExtensions.cs b/src/OrchardCore/OrchardCore.Users.Core/Extensions/ExternalLoginInfoExtensions.cs index c7417ec3c2f..0c5499f2bb2 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/Extensions/ExternalLoginInfoExtensions.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/Extensions/ExternalLoginInfoExtensions.cs @@ -5,6 +5,5 @@ namespace Microsoft.AspNetCore.Identity; public static class ExternalLoginInfoExtensions { public static string GetEmail(this ExternalLoginInfo info) - => info.Principal.FindFirstValue(ClaimTypes.Email) - ?? info.Principal.FindFirstValue("email"); + => info.Principal.FindFirstValue(ClaimTypes.Email) ?? info.Principal.FindFirstValue("email"); } From 139ca999e35af1fffb88c69a664d8502a17b623d Mon Sep 17 00:00:00 2001 From: tempcode Date: Wed, 12 Jun 2024 09:00:30 +0200 Subject: [PATCH 23/30] docs: updated comment in the AccountController about order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../OrchardCore.Users/Controllers/AccountController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 1d0d6096822..093b37986d5 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -96,7 +96,7 @@ public AccountController( _loginFormDisplayManager = loginFormDisplayManager; _updateModelAccessor = updateModelAccessor; _externalLoginHandlers = externalLoginHandlers; - // Reverse the order of services to prioritize external services first, placing them before the default implementation. + // Reverse the order of services to prioritize third-party implementations first, placing them before the default one. _userToExternalLoginProviders = userToExternalLoginProviders.Reverse(); H = htmlLocalizer; From c28fbca9f5896c41afd2c8b8cbfaa021f75e59b8 Mon Sep 17 00:00:00 2001 From: tempcode Date: Wed, 12 Jun 2024 09:01:43 +0200 Subject: [PATCH 24/30] style: brackets on a new line in AccountController MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../OrchardCore.Users/Controllers/AccountController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 093b37986d5..5c9f7b0df4c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -406,7 +406,8 @@ public async Task ExternalLoginCallback(string returnUrl = null, else { var userLocator = _userToExternalLoginProviders.FirstOrDefault(x => x.CanHandle(info)); - if (userLocator != null) { + if (userLocator != null) + { iUser = await userLocator.GetUserAsync(info); } From c3f4bbeea23b31dbb26b2b3d2714c93f4af38239 Mon Sep 17 00:00:00 2001 From: tempcode Date: Wed, 12 Jun 2024 10:05:10 +0200 Subject: [PATCH 25/30] style(Users.Abstractions): change name to interface feat(Users.Abstractions): remove GetIdentifierKey style(Users.Core): change name to default service style(Users): change name to mappers prop and local var --- .../Controllers/AccountController.cs | 25 ++++++------------- .../Views/Account/LinkExternalLogin.cshtml | 9 +------ ...ginProvider.cs => IExternalLoginMapper.cs} | 9 +------ .../UsersServiceCollectionExtensions.cs | 2 +- ...vider.cs => DefaultExternalLoginMapper.cs} | 7 ++---- 5 files changed, 13 insertions(+), 39 deletions(-) rename src/OrchardCore/OrchardCore.Users.Abstractions/Services/{IUserToExternalLoginProvider.cs => IExternalLoginMapper.cs} (76%) rename src/OrchardCore/OrchardCore.Users.Core/Services/{DefaultUserToExternalLoginProvider.cs => DefaultExternalLoginMapper.cs} (67%) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 5c9f7b0df4c..fcb569c4861 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Security.Claims; -using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Settings; using System.Threading.Tasks; @@ -52,7 +51,7 @@ public class AccountController : AccountBaseController private readonly IClock _clock; private readonly IDistributedCache _distributedCache; private readonly IEnumerable _externalLoginHandlers; - private readonly IEnumerable _userToExternalLoginProviders; + private readonly IEnumerable _externalLoginMappers; private static readonly JsonMergeSettings _jsonMergeSettings = new() { @@ -80,7 +79,7 @@ public AccountController( IDisplayManager loginFormDisplayManager, IUpdateModelAccessor updateModelAccessor, IEnumerable externalLoginHandlers, - IEnumerable userToExternalLoginProviders) + IEnumerable externalLoginMappers) { _signInManager = signInManager; _userManager = userManager; @@ -97,7 +96,7 @@ public AccountController( _updateModelAccessor = updateModelAccessor; _externalLoginHandlers = externalLoginHandlers; // Reverse the order of services to prioritize third-party implementations first, placing them before the default one. - _userToExternalLoginProviders = userToExternalLoginProviders.Reverse(); + _externalLoginMappers = externalLoginMappers.Reverse(); H = htmlLocalizer; S = stringLocalizer; @@ -405,10 +404,10 @@ public async Task ExternalLoginCallback(string returnUrl = null, } else { - var userLocator = _userToExternalLoginProviders.FirstOrDefault(x => x.CanHandle(info)); - if (userLocator != null) + var extLoginMapper = _externalLoginMappers.FirstOrDefault(x => x.CanHandle(info)); + if (extLoginMapper != null) { - iUser = await userLocator.GetUserAsync(info); + iUser = await extLoginMapper.GetUserAsync(info); } ViewData["ReturnUrl"] = returnUrl; @@ -429,14 +428,6 @@ public async Task ExternalLoginCallback(string returnUrl = null, // Link external login to an existing user ViewData["UserName"] = iUser.UserName; - if (userLocator != null) - { - ViewData["ExternalUserIdentifier"] = userLocator.GetIdentifierKey(info); - } - else - { - ViewData["ExternalUserIdentifier"] = info.GetEmail(); - } return View(nameof(LinkExternalLogin)); } @@ -658,8 +649,8 @@ public async Task LinkExternalLogin(LinkExternalLoginViewModel mo return NotFound(); } - var userLocator = _userToExternalLoginProviders.FirstOrDefault(x => x.CanHandle(info)); - var user = await userLocator?.GetUserAsync(info); + var extLoginMapper = _externalLoginMappers.FirstOrDefault(x => x.CanHandle(info)); + var user = await extLoginMapper?.GetUserAsync(info); if (user == null) { diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml index 0722ebc4d58..35541cd96e5 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml @@ -7,7 +7,7 @@

@T["Link your account."]

- @T["You've successfully authenticated with {0}. You already have an account associated with {1}. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"], ViewData["ExternalUserIdentifier"]] + @T["You've successfully authenticated with {0}. You already have an account associated with this external login. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"]]


@@ -19,13 +19,6 @@
-
- -
- -
-
-
diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs similarity index 76% rename from src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs rename to src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs index 6d9c9810493..5a5d7f8fe96 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs @@ -11,7 +11,7 @@ namespace OrchardCore.Users; /// Implement this interface if you want to provide an alternative way to link a local user with an external login provider. /// /// -public interface IUserToExternalLoginProvider +public interface IExternalLoginMapper { /// /// Checks if the implementation can handle the given external login information. @@ -30,11 +30,4 @@ public interface IUserToExternalLoginProvider /// An instance of if there's a local account matching the external login data; otherwise, . /// Task GetUserAsync(ExternalLoginInfo info); - - /// - /// Gets the identifier's key used by the implementation. - /// - /// The external login information. - /// A string identifier denoting the property name utilized for user identification. - string GetIdentifierKey(ExternalLoginInfo info); } diff --git a/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs index da747cc9cd1..46c65483086 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs @@ -39,7 +39,7 @@ public static IServiceCollection AddUsers(this IServiceCollection services) services.TryAddScoped>(sp => sp.GetRequiredService()); services.TryAddScoped>(sp => sp.GetRequiredService()); - services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.TryAddScoped>(sp => sp.GetRequiredService()); diff --git a/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs b/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs similarity index 67% rename from src/OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs rename to src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs index 223644a005e..60a51e04ff7 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultUserToExternalLoginProvider.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs @@ -3,11 +3,11 @@ namespace OrchardCore.Users.Services; -public class DefaultUserToExternalLoginProvider : IUserToExternalLoginProvider +public class DefaultExternalLoginMapper : IExternalLoginMapper { private readonly UserManager _userManager; - public DefaultUserToExternalLoginProvider(UserManager userManager) + public DefaultExternalLoginMapper(UserManager userManager) { _userManager = userManager; } @@ -21,7 +21,4 @@ public async Task GetUserAsync(ExternalLoginInfo info) return !string.IsNullOrWhiteSpace(email) ? await _userManager.FindByEmailAsync(email) : null; } - - public string GetIdentifierKey(ExternalLoginInfo info) - => info.GetEmail(); } From 5fd181a35f2a86b23b4ac251a11b463256415cbc Mon Sep 17 00:00:00 2001 From: tempcode Date: Wed, 12 Jun 2024 11:44:24 +0200 Subject: [PATCH 26/30] style: from GetUserAsync to FindByLoginAsync styl: updated text in razor page --- .../OrchardCore.Users/Controllers/AccountController.cs | 4 ++-- .../OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml | 2 +- .../Services/IExternalLoginMapper.cs | 2 +- .../Services/DefaultExternalLoginMapper.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index fcb569c4861..303f74f2ea8 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -407,7 +407,7 @@ public async Task ExternalLoginCallback(string returnUrl = null, var extLoginMapper = _externalLoginMappers.FirstOrDefault(x => x.CanHandle(info)); if (extLoginMapper != null) { - iUser = await extLoginMapper.GetUserAsync(info); + iUser = await extLoginMapper.FindByLoginAsync(info); } ViewData["ReturnUrl"] = returnUrl; @@ -650,7 +650,7 @@ public async Task LinkExternalLogin(LinkExternalLoginViewModel mo } var extLoginMapper = _externalLoginMappers.FirstOrDefault(x => x.CanHandle(info)); - var user = await extLoginMapper?.GetUserAsync(info); + var user = await extLoginMapper?.FindByLoginAsync(info); if (user == null) { diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml index 35541cd96e5..d31e28d1d31 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Account/LinkExternalLogin.cshtml @@ -7,7 +7,7 @@

@T["Link your account."]

- @T["You've successfully authenticated with {0}. You already have an account associated with this external login. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"]] + @T["You've successfully authenticated with {0}. You already have an account that can be linked with this external login. Enter your local account password and click the Register button to link the accounts and finish logging in.", ViewData["LoginProvider"]]


diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs index 5a5d7f8fe96..b528e0db394 100644 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs +++ b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs @@ -29,5 +29,5 @@ public interface IExternalLoginMapper /// /// An instance of if there's a local account matching the external login data; otherwise, . /// - Task GetUserAsync(ExternalLoginInfo info); + Task FindByLoginAsync(ExternalLoginInfo info); } diff --git a/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs b/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs index 60a51e04ff7..befb719c7e2 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs @@ -15,7 +15,7 @@ public DefaultExternalLoginMapper(UserManager userManager) public bool CanHandle(ExternalLoginInfo info) => true; - public async Task GetUserAsync(ExternalLoginInfo info) + public async Task FindByLoginAsync(ExternalLoginInfo info) { var email = info.GetEmail(); From 5c378b85d7ac4c296d315b3d77fe65a133f0fb6a Mon Sep 17 00:00:00 2001 From: tempcode Date: Sat, 15 Jun 2024 11:29:53 +0200 Subject: [PATCH 27/30] fix: removed IExternalLoginMapper fix: removed DefaultExternalLoginMapper fix: restored UsersServiceCollectionExtensions fix: implemente check of RequireUniqueEmail in AccountController --- .../Controllers/AccountController.cs | 51 +++++++++---------- .../Services/IExternalLoginMapper.cs | 33 ------------ .../UsersServiceCollectionExtensions.cs | 2 - .../Services/DefaultExternalLoginMapper.cs | 24 --------- 4 files changed, 24 insertions(+), 86 deletions(-) delete mode 100644 src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs delete mode 100644 src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 303f74f2ea8..65121b5fca7 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -14,6 +14,7 @@ using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using OrchardCore.ContentManagement; using OrchardCore.DisplayManagement; @@ -51,8 +52,7 @@ public class AccountController : AccountBaseController private readonly IClock _clock; private readonly IDistributedCache _distributedCache; private readonly IEnumerable _externalLoginHandlers; - private readonly IEnumerable _externalLoginMappers; - + private readonly IdentityOptions _identityOptions; private static readonly JsonMergeSettings _jsonMergeSettings = new() { MergeArrayHandling = MergeArrayHandling.Replace, @@ -79,7 +79,7 @@ public AccountController( IDisplayManager loginFormDisplayManager, IUpdateModelAccessor updateModelAccessor, IEnumerable externalLoginHandlers, - IEnumerable externalLoginMappers) + IOptions identityOptions) { _signInManager = signInManager; _userManager = userManager; @@ -95,8 +95,7 @@ public AccountController( _loginFormDisplayManager = loginFormDisplayManager; _updateModelAccessor = updateModelAccessor; _externalLoginHandlers = externalLoginHandlers; - // Reverse the order of services to prioritize third-party implementations first, placing them before the default one. - _externalLoginMappers = externalLoginMappers.Reverse(); + _identityOptions = identityOptions.Value; H = htmlLocalizer; S = stringLocalizer; @@ -404,32 +403,31 @@ public async Task ExternalLoginCallback(string returnUrl = null, } else { - var extLoginMapper = _externalLoginMappers.FirstOrDefault(x => x.CanHandle(info)); - if (extLoginMapper != null) + if (_identityOptions.User.RequireUniqueEmail) { - iUser = await extLoginMapper.FindByLoginAsync(info); - } + iUser = await _userManager.FindByEmailAsync(info.GetEmail()); - ViewData["ReturnUrl"] = returnUrl; - ViewData["LoginProvider"] = info.LoginProvider; + ViewData["ReturnUrl"] = returnUrl; + ViewData["LoginProvider"] = info.LoginProvider; - if (iUser != null) - { - if (iUser is User userToLink && registrationSettings.UsersMustValidateEmail && !userToLink.EmailConfirmed) + if (iUser != null) { - return RedirectToAction(nameof(EmailConfirmationController.ConfirmEmailSent), - new - { - Area = UserConstants.Features.Users, - Controller = typeof(EmailConfirmationController).ControllerName(), - ReturnUrl = returnUrl, - }); - } + if (iUser is User userToLink && registrationSettings.UsersMustValidateEmail && !userToLink.EmailConfirmed) + { + return RedirectToAction(nameof(EmailConfirmationController.ConfirmEmailSent), + new + { + Area = UserConstants.Features.Users, + Controller = typeof(EmailConfirmationController).ControllerName(), + ReturnUrl = returnUrl, + }); + } - // Link external login to an existing user - ViewData["UserName"] = iUser.UserName; + // Link external login to an existing user + ViewData["UserName"] = iUser.UserName; - return View(nameof(LinkExternalLogin)); + return View(nameof(LinkExternalLogin)); + } } // No user could be matched, check if a new user can register. @@ -649,8 +647,7 @@ public async Task LinkExternalLogin(LinkExternalLoginViewModel mo return NotFound(); } - var extLoginMapper = _externalLoginMappers.FirstOrDefault(x => x.CanHandle(info)); - var user = await extLoginMapper?.FindByLoginAsync(info); + var user = await _userManager.FindByEmailAsync(info.GetEmail()); if (user == null) { diff --git a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs b/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs deleted file mode 100644 index b528e0db394..00000000000 --- a/src/OrchardCore/OrchardCore.Users.Abstractions/Services/IExternalLoginMapper.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity; - -namespace OrchardCore.Users; - -/// -/// Service to link a local user with an externally authenticated user during registration. -/// -/// -/// -/// Implement this interface if you want to provide an alternative way to link a local user with an external login provider. -/// -/// -public interface IExternalLoginMapper -{ - /// - /// Checks if the implementation can handle the given external login information. - /// - /// The external login information. - /// - /// if the service can handle the given external login information, otherwise. - /// - bool CanHandle(ExternalLoginInfo info); - - /// - /// Retrieves a local user account that corresponds to the provided external login information, if one exists. - /// - /// The external login information. - /// - /// An instance of if there's a local account matching the external login data; otherwise, . - /// - Task FindByLoginAsync(ExternalLoginInfo info); -} diff --git a/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs index 46c65483086..4d071924f84 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs @@ -39,8 +39,6 @@ public static IServiceCollection AddUsers(this IServiceCollection services) services.TryAddScoped>(sp => sp.GetRequiredService()); services.TryAddScoped>(sp => sp.GetRequiredService()); - services.AddScoped(); - services.AddScoped(); services.TryAddScoped>(sp => sp.GetRequiredService()); services.TryAddScoped>(sp => sp.GetRequiredService()); diff --git a/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs b/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs deleted file mode 100644 index befb719c7e2..00000000000 --- a/src/OrchardCore/OrchardCore.Users.Core/Services/DefaultExternalLoginMapper.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity; - -namespace OrchardCore.Users.Services; - -public class DefaultExternalLoginMapper : IExternalLoginMapper -{ - private readonly UserManager _userManager; - - public DefaultExternalLoginMapper(UserManager userManager) - { - _userManager = userManager; - } - - public bool CanHandle(ExternalLoginInfo info) - => true; - - public async Task FindByLoginAsync(ExternalLoginInfo info) - { - var email = info.GetEmail(); - - return !string.IsNullOrWhiteSpace(email) ? await _userManager.FindByEmailAsync(email) : null; - } -} From f2faf1735d5577ad85bd950dd59f94d1459e09f3 Mon Sep 17 00:00:00 2001 From: tempcode Date: Sat, 15 Jun 2024 22:21:23 +0200 Subject: [PATCH 28/30] fix: improve if declaration fix: restored check of the email value --- .../Controllers/AccountController.cs | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 65121b5fca7..0cb6989a7cf 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -403,33 +403,36 @@ public async Task ExternalLoginCallback(string returnUrl = null, } else { - if (_identityOptions.User.RequireUniqueEmail) + var email = info.GetEmail(); + + if (_identityOptions.User.RequireUniqueEmail && !string.IsNullOrWhiteSpace(email)) { - iUser = await _userManager.FindByEmailAsync(info.GetEmail()); + iUser = await _userManager.FindByEmailAsync(email); + } - ViewData["ReturnUrl"] = returnUrl; - ViewData["LoginProvider"] = info.LoginProvider; + ViewData["ReturnUrl"] = returnUrl; + ViewData["LoginProvider"] = info.LoginProvider; - if (iUser != null) + if (iUser != null) + { + if (iUser is User userToLink && registrationSettings.UsersMustValidateEmail && !userToLink.EmailConfirmed) { - if (iUser is User userToLink && registrationSettings.UsersMustValidateEmail && !userToLink.EmailConfirmed) - { - return RedirectToAction(nameof(EmailConfirmationController.ConfirmEmailSent), - new - { - Area = UserConstants.Features.Users, - Controller = typeof(EmailConfirmationController).ControllerName(), - ReturnUrl = returnUrl, - }); - } + return RedirectToAction(nameof(EmailConfirmationController.ConfirmEmailSent), + new + { + Area = UserConstants.Features.Users, + Controller = typeof(EmailConfirmationController).ControllerName(), + ReturnUrl = returnUrl, + }); + } - // Link external login to an existing user - ViewData["UserName"] = iUser.UserName; + // Link external login to an existing user + ViewData["UserName"] = iUser.UserName; - return View(nameof(LinkExternalLogin)); - } + return View(nameof(LinkExternalLogin)); } + // No user could be matched, check if a new user can register. if (registrationSettings.UsersCanRegister == UserRegistrationType.NoRegistration) { From da86ae670e5470ae38c90e85b4cc9f8e3e8ddd2d Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 17 Jun 2024 13:39:27 -0700 Subject: [PATCH 29/30] Update AccountController.cs --- .../OrchardCore.Users/Controllers/AccountController.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 0cb6989a7cf..1fa66b80519 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -432,7 +432,6 @@ public async Task ExternalLoginCallback(string returnUrl = null, return View(nameof(LinkExternalLogin)); } - // No user could be matched, check if a new user can register. if (registrationSettings.UsersCanRegister == UserRegistrationType.NoRegistration) { From d3e1010522034b166aebfecd66560c738cc38f64 Mon Sep 17 00:00:00 2001 From: tempcode Date: Tue, 18 Jun 2024 14:35:34 +0200 Subject: [PATCH 30/30] Update src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs Co-authored-by: Hisham Bin Ateya --- .../OrchardCore.Users/Controllers/AccountController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs index 1fa66b80519..4b2f714f74e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AccountController.cs @@ -53,6 +53,7 @@ public class AccountController : AccountBaseController private readonly IDistributedCache _distributedCache; private readonly IEnumerable _externalLoginHandlers; private readonly IdentityOptions _identityOptions; + private static readonly JsonMergeSettings _jsonMergeSettings = new() { MergeArrayHandling = MergeArrayHandling.Replace,