From 54704eb57b35104a7d96e70dcbe03412ed4d751e Mon Sep 17 00:00:00 2001 From: "Dhruv Mathur [SSW]" Date: Thu, 30 Nov 2023 10:13:36 +1100 Subject: [PATCH 1/4] Update rule.md --- .../rule.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/integrate-identityserver-with-an-existing-user-store/rule.md b/rules/integrate-identityserver-with-an-existing-user-store/rule.md index 571d30562f8..b219321ab02 100644 --- a/rules/integrate-identityserver-with-an-existing-user-store/rule.md +++ b/rules/integrate-identityserver-with-an-existing-user-store/rule.md @@ -1,7 +1,7 @@ --- type: rule title: Do you know how to migrate an existing user store to an ExternalAuthProvider? -uri: migrate-an-existing-user-store-to-externalauthprovider +uri: integrate-identityserver-with-an-existing-user-store authors: - title: "Dhruv Mathur" url: https://www.ssw.com.au/people/dhruv/ From 0cc94dfb439486f89bfbf6580fc4f4bf273facae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 29 Nov 2023 23:16:07 +0000 Subject: [PATCH 2/4] Auto-fix Markdown files --- .../rule.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/rules/integrate-identityserver-with-an-existing-user-store/rule.md b/rules/integrate-identityserver-with-an-existing-user-store/rule.md index b219321ab02..4aa64eb3eac 100644 --- a/rules/integrate-identityserver-with-an-existing-user-store/rule.md +++ b/rules/integrate-identityserver-with-an-existing-user-store/rule.md @@ -8,13 +8,13 @@ authors: created: 2023-10-31T04:31:12.396Z guid: 38a5988b-1740-4120-840d-116ad6e91566 --- -When integrating an external authentication provider (IdentityServer, Azure AD or Microsoft Entra ID etc.) with an existing ASP .NET Core application which uses ASP .NET Core Identity, challenges arise due to different user identification systems. +When integrating an external authentication provider (IdentityServer, Azure AD or Microsoft Entra ID etc.) with an existing ASP .NET Core application which uses ASP .NET Core Identity, challenges arise due to different user identification systems. -On the ExternalAuthProvider side, users are typically recognised by a unique SubId within their issued token after authentication. In contrast, an application's existing user store might use its own unique user ID, possibly combined with other data. +On the ExternalAuthProvider side, users are typically recognised by a unique SubId within their issued token after authentication. In contrast, an application's existing user store might use its own unique user ID, possibly combined with other data. The above discrepancy creates the need to effectively map or correlate the the user with SubId from the ExternalAuthProvider to the corresponding user with user ID within the app's user store. -## Two essential scenarios arise when integrating the ExternalAuthProvider: +## Two essential scenarios arise when integrating the ExternalAuthProvider ### 1. Pre-existing Company Users @@ -37,9 +37,11 @@ var existingUserByExternalLogin = await _userManager.FindByLoginAsync(EXTERNAL_A ```csharp var userByUserName = await _userManager.FindByEmailAsync(emailFromIdentityServer); ``` + ::: good Figure: Retrieving existing user by using the Email claim from the JWT token utilising the FindByEmailAsync() from the UserManager class. ::: + * For users known to your application but not authenticated via the ExternalAuthProvider: * Retrieve the SubId from the JWT token provided by the ExternalAuthProvider. @@ -49,6 +51,7 @@ Figure: Retrieving existing user by using the Email claim from the JWT token uti var subId = token.Claims.FirstOrDefault(c => c.Type == "sub"); await _userManager.AddLoginAsync(newUser, new UserLoginInfo(EXTERNAL_AUTH_PROVIDER, subId)); ``` + ::: greybox Note: In the example above the "EXTERNAL\_AUTH\_PROVIDER" is a constant which contains the identifier for your external authentication provider. e.g. IDENTITY\_SERVER\_EXTERNAL\_LOGIN = "IdentityServer" ::: @@ -57,7 +60,7 @@ Note: In the example above the "EXTERNAL\_AUTH\_PROVIDER" is a constant which co * For all subsequent logins, employ the [`FindAsync(new UserLoginInfo())`](https://learn.microsoft.com/en-us/previous-versions/aspnet/dn497605(v=vs.108)) method. -**Benefits**: +**Benefits**: * Seamless authentication experience for existing users. * Avoids custom fields in the ApplicationUser model, leveraging existing ASP .NET Identity Core methods like [`AddLoginAsync`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.addloginasync?view=aspnetcore-8.0) and [`FindAsync`](https://learn.microsoft.com/en-us/previous-versions/aspnet/dn497605(v=vs.108)). @@ -77,8 +80,6 @@ Note: In the example above the "EXTERNAL\_AUTH\_PROVIDER" is a constant which co var existingUser = await _userManager.FindByEmailAsync(emailFromIdentityServer); ``` - - * **User Creation & SubId Association**: * Register by creating a new user in your application's store using claims provided by the ExternalAuthProvider (e.g., first name, last name, email). @@ -107,6 +108,7 @@ Note: In the example above extraction of claims may vary based on how you access var subId = token.Claims.FirstOrDefault(c => c.Type == "sub"); await _userManager.AddLoginAsync(newUser, new UserLoginInfo(EXTERNAL_AUTH_PROVIDER, subId)); ``` + * **Future Authentications**: * Finally for all subsequent logins use the [`FindByLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyloginasync?view=aspnetcore-7.0) method to check if the user already exists. From 7088572e09594be66ec4e9101ac7e1cf79e54ad0 Mon Sep 17 00:00:00 2001 From: "Dhruv Mathur [SSW]" Date: Thu, 30 Nov 2023 10:45:55 +1100 Subject: [PATCH 3/4] semantic changes for better readability --- .../rule.md | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/rules/integrate-identityserver-with-an-existing-user-store/rule.md b/rules/integrate-identityserver-with-an-existing-user-store/rule.md index 4aa64eb3eac..806e16f32f0 100644 --- a/rules/integrate-identityserver-with-an-existing-user-store/rule.md +++ b/rules/integrate-identityserver-with-an-existing-user-store/rule.md @@ -8,41 +8,37 @@ authors: created: 2023-10-31T04:31:12.396Z guid: 38a5988b-1740-4120-840d-116ad6e91566 --- -When integrating an external authentication provider (IdentityServer, Azure AD or Microsoft Entra ID etc.) with an existing ASP .NET Core application which uses ASP .NET Core Identity, challenges arise due to different user identification systems. +When integrating an external authentication provider (IdentityServer, Azure AD or Microsoft Entra ID etc.) with an existing ASP .NET Core application which uses ASP .NET Core Identity, challenges arise due to different user identification systems. -On the ExternalAuthProvider side, users are typically recognised by a unique SubId within their issued token after authentication. In contrast, an application's existing user store might use its own unique user ID, possibly combined with other data. +On the ExternalAuthProvider side, users are typically recognised by a unique SubId within their issued token after authentication. In contrast, an application's existing user store might use its own unique user ID, possibly combined with other data. The above discrepancy creates the need to effectively map or correlate the the user with SubId from the ExternalAuthProvider to the corresponding user with user ID within the app's user store. -## Two essential scenarios arise when integrating the ExternalAuthProvider +Two essential scenarios arise when integrating the ExternalAuthProvider: -### 1. Pre-existing Company Users +## 1. Pre-existing Company Users -#### **Technical Integration & Benefits** +Addressing users already registered with company emails in the existing application user store now authenticating through the ExternalAuthProvider: -**Addressing users already registered with company emails in the existing application user store now authenticating through the ExternalAuthProvider:** - -* **SubId Check**: +**SubId Check**: * Begin by verifying if the user has an external login associated with the SubId from the ExternalAuthProvider in your application's user store using the [`FindByLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyloginasync?view=aspnetcore-7.0) method. If found, proceed with authentication by handling the request gracefully. ```csharp var existingUserByExternalLogin = await _userManager.FindByLoginAsync(EXTERNAL_AUTH_PROVIDER, subId); ``` - -* **Existing Users by Email Verification**: +**Existing Users by Email Verification**: * If there's no associated SubId, check if the email (provided by the ExternalAuthProvider during authentication available as one of the claims in the JWT token) exists in your application's user store. ```csharp var userByUserName = await _userManager.FindByEmailAsync(emailFromIdentityServer); ``` - ::: good Figure: Retrieving existing user by using the Email claim from the JWT token utilising the FindByEmailAsync() from the UserManager class. ::: -* For users known to your application but not authenticated via the ExternalAuthProvider: +**For users known to your application but not authenticated via the ExternalAuthProvider**: * Retrieve the SubId from the JWT token provided by the ExternalAuthProvider. * Use ASP .NET Core Identity's [`AddLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.addloginasync?view=aspnetcore-8.0) method to associate this SubId as an external login with the user's record. @@ -51,27 +47,24 @@ Figure: Retrieving existing user by using the Email claim from the JWT token uti var subId = token.Claims.FirstOrDefault(c => c.Type == "sub"); await _userManager.AddLoginAsync(newUser, new UserLoginInfo(EXTERNAL_AUTH_PROVIDER, subId)); ``` - ::: greybox Note: In the example above the "EXTERNAL\_AUTH\_PROVIDER" is a constant which contains the identifier for your external authentication provider. e.g. IDENTITY\_SERVER\_EXTERNAL\_LOGIN = "IdentityServer" ::: -* **Future Authentications**: +**Future Authentications**: * For all subsequent logins, employ the [`FindAsync(new UserLoginInfo())`](https://learn.microsoft.com/en-us/previous-versions/aspnet/dn497605(v=vs.108)) method. -**Benefits**: +**Benefits**: * Seamless authentication experience for existing users. * Avoids custom fields in the ApplicationUser model, leveraging existing ASP .NET Identity Core methods like [`AddLoginAsync`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.addloginasync?view=aspnetcore-8.0) and [`FindAsync`](https://learn.microsoft.com/en-us/previous-versions/aspnet/dn497605(v=vs.108)). -### 2. New ExternalAuthProvider Registrants - -#### **Technical Integration & Benefits** +## 2. New ExternalAuthProvider Registrants -**Incorporating users who are new to both the ExternalAuthProvider and the application:** +Incorporating users who are new to both the ExternalAuthProvider and the application: -* **Email Verification**: +**Email Verification**: * Check if the email provided by the ExternalAuthProvider during authentication exists in your application's user store by using ASP .NET Identity Core methods like [`FindByEmailAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyemailasync?view=aspnetcore-7.0). * If it doesn't, this indicates the user is new. @@ -80,7 +73,8 @@ Note: In the example above the "EXTERNAL\_AUTH\_PROVIDER" is a constant which co var existingUser = await _userManager.FindByEmailAsync(emailFromIdentityServer); ``` -* **User Creation & SubId Association**: + +**User Creation & SubId Association**: * Register by creating a new user in your application's store using claims provided by the ExternalAuthProvider (e.g., first name, last name, email). @@ -108,8 +102,7 @@ Note: In the example above extraction of claims may vary based on how you access var subId = token.Claims.FirstOrDefault(c => c.Type == "sub"); await _userManager.AddLoginAsync(newUser, new UserLoginInfo(EXTERNAL_AUTH_PROVIDER, subId)); ``` - -* **Future Authentications**: +**Future Authentications**: * Finally for all subsequent logins use the [`FindByLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyloginasync?view=aspnetcore-7.0) method to check if the user already exists. From c42973f585a8119fad53678b76929eb1446b38f2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 29 Nov 2023 23:46:50 +0000 Subject: [PATCH 4/4] Auto-fix Markdown files --- .../rule.md | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/rules/integrate-identityserver-with-an-existing-user-store/rule.md b/rules/integrate-identityserver-with-an-existing-user-store/rule.md index 806e16f32f0..0f4c31c0b52 100644 --- a/rules/integrate-identityserver-with-an-existing-user-store/rule.md +++ b/rules/integrate-identityserver-with-an-existing-user-store/rule.md @@ -8,9 +8,9 @@ authors: created: 2023-10-31T04:31:12.396Z guid: 38a5988b-1740-4120-840d-116ad6e91566 --- -When integrating an external authentication provider (IdentityServer, Azure AD or Microsoft Entra ID etc.) with an existing ASP .NET Core application which uses ASP .NET Core Identity, challenges arise due to different user identification systems. +When integrating an external authentication provider (IdentityServer, Azure AD or Microsoft Entra ID etc.) with an existing ASP .NET Core application which uses ASP .NET Core Identity, challenges arise due to different user identification systems. -On the ExternalAuthProvider side, users are typically recognised by a unique SubId within their issued token after authentication. In contrast, an application's existing user store might use its own unique user ID, possibly combined with other data. +On the ExternalAuthProvider side, users are typically recognised by a unique SubId within their issued token after authentication. In contrast, an application's existing user store might use its own unique user ID, possibly combined with other data. The above discrepancy creates the need to effectively map or correlate the the user with SubId from the ExternalAuthProvider to the corresponding user with user ID within the app's user store. @@ -22,40 +22,43 @@ Addressing users already registered with company emails in the existing applicat **SubId Check**: - * Begin by verifying if the user has an external login associated with the SubId from the ExternalAuthProvider in your application's user store using the [`FindByLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyloginasync?view=aspnetcore-7.0) method. If found, proceed with authentication by handling the request gracefully. +* Begin by verifying if the user has an external login associated with the SubId from the ExternalAuthProvider in your application's user store using the [`FindByLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyloginasync?view=aspnetcore-7.0) method. If found, proceed with authentication by handling the request gracefully. ```csharp var existingUserByExternalLogin = await _userManager.FindByLoginAsync(EXTERNAL_AUTH_PROVIDER, subId); ``` + **Existing Users by Email Verification**: - * If there's no associated SubId, check if the email (provided by the ExternalAuthProvider during authentication available as one of the claims in the JWT token) exists in your application's user store. +* If there's no associated SubId, check if the email (provided by the ExternalAuthProvider during authentication available as one of the claims in the JWT token) exists in your application's user store. ```csharp var userByUserName = await _userManager.FindByEmailAsync(emailFromIdentityServer); ``` + ::: good Figure: Retrieving existing user by using the Email claim from the JWT token utilising the FindByEmailAsync() from the UserManager class. ::: **For users known to your application but not authenticated via the ExternalAuthProvider**: - * Retrieve the SubId from the JWT token provided by the ExternalAuthProvider. - * Use ASP .NET Core Identity's [`AddLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.addloginasync?view=aspnetcore-8.0) method to associate this SubId as an external login with the user's record. +* Retrieve the SubId from the JWT token provided by the ExternalAuthProvider. +* Use ASP .NET Core Identity's [`AddLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.addloginasync?view=aspnetcore-8.0) method to associate this SubId as an external login with the user's record. ```csharp var subId = token.Claims.FirstOrDefault(c => c.Type == "sub"); await _userManager.AddLoginAsync(newUser, new UserLoginInfo(EXTERNAL_AUTH_PROVIDER, subId)); ``` + ::: greybox Note: In the example above the "EXTERNAL\_AUTH\_PROVIDER" is a constant which contains the identifier for your external authentication provider. e.g. IDENTITY\_SERVER\_EXTERNAL\_LOGIN = "IdentityServer" ::: **Future Authentications**: - * For all subsequent logins, employ the [`FindAsync(new UserLoginInfo())`](https://learn.microsoft.com/en-us/previous-versions/aspnet/dn497605(v=vs.108)) method. +* For all subsequent logins, employ the [`FindAsync(new UserLoginInfo())`](https://learn.microsoft.com/en-us/previous-versions/aspnet/dn497605(v=vs.108)) method. -**Benefits**: +**Benefits**: * Seamless authentication experience for existing users. * Avoids custom fields in the ApplicationUser model, leveraging existing ASP .NET Identity Core methods like [`AddLoginAsync`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.addloginasync?view=aspnetcore-8.0) and [`FindAsync`](https://learn.microsoft.com/en-us/previous-versions/aspnet/dn497605(v=vs.108)). @@ -66,17 +69,16 @@ Incorporating users who are new to both the ExternalAuthProvider and the applica **Email Verification**: - * Check if the email provided by the ExternalAuthProvider during authentication exists in your application's user store by using ASP .NET Identity Core methods like [`FindByEmailAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyemailasync?view=aspnetcore-7.0). - * If it doesn't, this indicates the user is new. +* Check if the email provided by the ExternalAuthProvider during authentication exists in your application's user store by using ASP .NET Identity Core methods like [`FindByEmailAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyemailasync?view=aspnetcore-7.0). +* If it doesn't, this indicates the user is new. ```csharp var existingUser = await _userManager.FindByEmailAsync(emailFromIdentityServer); ``` - **User Creation & SubId Association**: - * Register by creating a new user in your application's store using claims provided by the ExternalAuthProvider (e.g., first name, last name, email). +* Register by creating a new user in your application's store using claims provided by the ExternalAuthProvider (e.g., first name, last name, email). ```csharp var newUser = new Domain.Entities.ApplicationUser @@ -102,9 +104,10 @@ Note: In the example above extraction of claims may vary based on how you access var subId = token.Claims.FirstOrDefault(c => c.Type == "sub"); await _userManager.AddLoginAsync(newUser, new UserLoginInfo(EXTERNAL_AUTH_PROVIDER, subId)); ``` + **Future Authentications**: - * Finally for all subsequent logins use the [`FindByLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyloginasync?view=aspnetcore-7.0) method to check if the user already exists. +* Finally for all subsequent logins use the [`FindByLoginAsync()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.findbyloginasync?view=aspnetcore-7.0) method to check if the user already exists. ```csharp var existingUser = await _userManager.FindByLoginAsync(EXTERNAL_AUTH_PROVIDER, subId));