From 272ca7b315c224ebd71929c12826ab78172c2f2e Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Sat, 28 Mar 2020 05:13:28 +0300 Subject: [PATCH 1/6] added initial post --- docs/en/Blog-Posts/2020-04-01/Post.md | 176 ++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 docs/en/Blog-Posts/2020-04-01/Post.md diff --git a/docs/en/Blog-Posts/2020-04-01/Post.md b/docs/en/Blog-Posts/2020-04-01/Post.md new file mode 100644 index 0000000000..bc3148ec5e --- /dev/null +++ b/docs/en/Blog-Posts/2020-04-01/Post.md @@ -0,0 +1,176 @@ +# Using Azure Active Directory Authentication in ABP Applications + +## Introduction + +This post demonstrates how to integrate AzureAD to an ABP application that enables users to sign in using OAuth 2.0 with credentials from Azure Active Directory. + +Adding Azure Active Directory is pretty straightforward in Abp framework. Couple of configurations needs to be done correctly. + +There will be two samples of connections for better covarage; + +- **AddOpenIdConnect** (Default Microsoft.AspNetCore.Authentication.OpenIdConnect package) +- **AddAzureAD** (Microsoft.AspNetCore.Authentication.AzureAD.UI package) + + + +## AddOpenIdConnect + +#### **Update your `appsettings.json`** + +In your **.Web** application, add the following section filled with your AzureAD application settings. + +````xml + "AzureAd": { + "Instance": "https://login.microsoftonline.com/", + "TenantId": "", + "ClientSecret": "", + "Domain": "domain.onmicrosoft.com", + "CallbackPath": "/signin-azuread-oidc" + } +```` + +Modify `ConfigureAuthentication` method of your **BookStoreWebModule** with the following: + +````xml +private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration) + { + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier); + + context.Services.AddAuthentication() + .AddIdentityServerAuthentication(options => + { + options.Authority = configuration["AuthServer:Authority"]; + options.RequireHttpsMetadata = false; + options.ApiName = "BookStore"; + }) + .AddOpenIdConnect("AzureOpenId", "AzureAD", options => + { + options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"]; + options.ClientId = configuration["AzureAd:ClientId"]; + options.ResponseType = OpenIdConnectResponseType.CodeIdToken; + options.CallbackPath = configuration["AzureAd:CallbackPath"]; + options.ClientSecret = configuration["AzureAd:ClientSecret"]; + options.RequireHttpsMetadata = false; + options.SaveTokens = true; + options.GetClaimsFromUserInfoEndpoint = true; + }); + } +```` + + + +## AddAzureAD + +#### **Update your `appsettings.json`** + +Install `Microsoft.AspNetCore.Authentication.AzureAD.UI` package to your **.Web** application. + +In your **.Web** application, add the following section filled with your AzureAD application settings. + +Notice that you don't need to add `ClientSecret` when you are using `Microsoft.AspNetCore.Authentication.AzureAD.UI` package. + +````xml + "AzureAd": { + "Instance": "https://login.microsoftonline.com/", + "TenantId": "", + "Domain": "domain.onmicrosoft.com", + "CallbackPath": "/signin-azuread-oidc" + } +```` + +Modify `ConfigureAuthentication` method of your **BookStoreWebModule** with the following: + +````xml +private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration) + { + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier); + context.Services.AddAuthentication() + .AddIdentityServerAuthentication(options => + { + options.Authority = configuration["AuthServer:Authority"]; + options.RequireHttpsMetadata = false; + options.ApiName = "Acme.BookStore"; + }) + .AddAzureAD(options => configuration.Bind("AzureAd", options)); + + context.Services.Configure(AzureADDefaults.OpenIdScheme, options => + { + options.Authority = options.Authority + "/v2.0/"; + options.ClientId = configuration["AzureAd:ClientId"]; + options.CallbackPath = configuration["AzureAd:CallbackPath"]; + options.ResponseType = OpenIdConnectResponseType.IdToken; + options.RequireHttpsMetadata = false; + + options.TokenValidationParameters.ValidateIssuer = false; + options.GetClaimsFromUserInfoEndpoint = true; + options.SaveTokens = true; + options.SignInScheme = IdentityConstants.ExternalScheme; + + options.Scope.Add("email"); + }); + } +```` + + + +# FAQ + +* Help! `GetExternalLoginInfoAsync` returns `null`! + + * There can be 2 reasons for this; + + 1. You are trying to authenticate against wrong scheme. Check if you set **SignInScheme** to `IdentityConstants.ExternalScheme`: + + ````xml + options.SignInScheme = IdentityConstants.ExternalScheme; + ```` + + 2. Your `ClaimTypes.NameIdentifier` is null. Check if you added claim mapping: + + ````xml + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier); + ```` + + +* Help! I keep getting ***AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application*** error! + + * If you set your **CallbackPath** in appsettings as: + + ````xml + "AzureAd": { + ... + "CallbackPath": "/signin-azuread-oidc" + } + ```` + + your **Redirect URI** of your application in azure portal must be with domain like `https://localhost:44320/signin-azuread-oidc`, not only `/signin-azuread-oidc`. + +* How can I **debug/watch** which claims I get before they get mapped? + + * You can add a simple event under openid configuration to debug before mapping like: + + ````xml + options.Events.OnTokenValidated = (async context => + { + var claimsFromOidcProvider = context.Principal.Claims.ToList(); + await Task.CompletedTask; + }); + ```` + +* I want to debug further, how can I implement my custom **SignInManager**? + + * You can check [Customizing SignInManager in Abp Framework](link here) post. + +* I want to add extra properties to user while they are being created. How can I do that? + + * You can check [Customizing Login Page in Abp Framework]() post. + +* Why can't I see **External Register Page** after I sign in from external provider for the first time? + + * ABP framework automatically registers your user with supported email claim from your external authentication provider. You can change this behaviour by [Customizing Login Page in Abp Framework](will be link here). + From d305b39cb1b03022bd7358a9003473b70620a12f Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Sat, 28 Mar 2020 05:53:14 +0300 Subject: [PATCH 2/6] naming update --- docs/en/Blog-Posts/2020-04-01/Post.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Blog-Posts/2020-04-01/Post.md b/docs/en/Blog-Posts/2020-04-01/Post.md index bc3148ec5e..6650aabbe5 100644 --- a/docs/en/Blog-Posts/2020-04-01/Post.md +++ b/docs/en/Blog-Posts/2020-04-01/Post.md @@ -1,4 +1,4 @@ -# Using Azure Active Directory Authentication in ABP Applications +# Using Azure Active Directory Authentication in ABP ASP.NET Core MVC application ## Introduction From a3e990e33585f234cbafed9e071db2cff8ee4fdd Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Sat, 28 Mar 2020 15:19:44 +0300 Subject: [PATCH 3/6] removed client secret settings from openId --- docs/en/Blog-Posts/2020-04-01/Post.md | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/docs/en/Blog-Posts/2020-04-01/Post.md b/docs/en/Blog-Posts/2020-04-01/Post.md index 6650aabbe5..9b2f49cd51 100644 --- a/docs/en/Blog-Posts/2020-04-01/Post.md +++ b/docs/en/Blog-Posts/2020-04-01/Post.md @@ -13,8 +13,6 @@ There will be two samples of connections for better covarage; -## AddOpenIdConnect - #### **Update your `appsettings.json`** In your **.Web** application, add the following section filled with your AzureAD application settings. @@ -30,6 +28,10 @@ In your **.Web** application, add the following section filled with your AzureAD } ```` + + +## AddOpenIdConnect + Modify `ConfigureAuthentication` method of your **BookStoreWebModule** with the following: ````xml @@ -51,7 +53,6 @@ private void ConfigureAuthentication(ServiceConfigurationContext context, IConfi options.ClientId = configuration["AzureAd:ClientId"]; options.ResponseType = OpenIdConnectResponseType.CodeIdToken; options.CallbackPath = configuration["AzureAd:CallbackPath"]; - options.ClientSecret = configuration["AzureAd:ClientSecret"]; options.RequireHttpsMetadata = false; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; @@ -67,21 +68,7 @@ private void ConfigureAuthentication(ServiceConfigurationContext context, IConfi Install `Microsoft.AspNetCore.Authentication.AzureAD.UI` package to your **.Web** application. -In your **.Web** application, add the following section filled with your AzureAD application settings. - -Notice that you don't need to add `ClientSecret` when you are using `Microsoft.AspNetCore.Authentication.AzureAD.UI` package. - -````xml - "AzureAd": { - "Instance": "https://login.microsoftonline.com/", - "TenantId": "", - "Domain": "domain.onmicrosoft.com", - "CallbackPath": "/signin-azuread-oidc" - } -```` - -Modify `ConfigureAuthentication` method of your **BookStoreWebModule** with the following: +In your **.Web** application, add the following section filled with your AzureAD application settings. Modify `ConfigureAuthentication` method of your **BookStoreWebModule** with the following: ````xml private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration) From 0be742fa0628c62aa96fa4d9a97b1f0f991c207f Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Sat, 28 Mar 2020 15:36:43 +0300 Subject: [PATCH 4/6] updated post --- docs/en/Blog-Posts/2020-04-01/Post.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/en/Blog-Posts/2020-04-01/Post.md b/docs/en/Blog-Posts/2020-04-01/Post.md index 9b2f49cd51..b57883ac8b 100644 --- a/docs/en/Blog-Posts/2020-04-01/Post.md +++ b/docs/en/Blog-Posts/2020-04-01/Post.md @@ -22,7 +22,6 @@ In your **.Web** application, add the following section filled with your AzureAD "Instance": "https://login.microsoftonline.com/", "TenantId": "", - "ClientSecret": "", "Domain": "domain.onmicrosoft.com", "CallbackPath": "/signin-azuread-oidc" } @@ -108,7 +107,7 @@ private void ConfigureAuthentication(ServiceConfigurationContext context, IConfi * Help! `GetExternalLoginInfoAsync` returns `null`! - * There can be 2 reasons for this; + * **There** can be 2 reasons for this; 1. You are trying to authenticate against wrong scheme. Check if you set **SignInScheme** to `IdentityConstants.ExternalScheme`: @@ -137,6 +136,17 @@ private void ConfigureAuthentication(ServiceConfigurationContext context, IConfi your **Redirect URI** of your application in azure portal must be with domain like `https://localhost:44320/signin-azuread-oidc`, not only `/signin-azuread-oidc`. +* Help! I am getting ***System.ArgumentNullException: Value cannot be null. (Parameter 'userName')*** error! + + + * This occurs when you use Azure Authority **v2.0 endpoint** without requesting `email` scope. [Abp checks unique email to create user](https://github.com/abpframework/abp/blob/037ef9abe024c03c1f89ab6c933710bcfe3f5c93/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs#L208). Simply add + + ````xml + options.Scope.Add("email"); + ```` + + to your openid configuration. + * How can I **debug/watch** which claims I get before they get mapped? * You can add a simple event under openid configuration to debug before mapping like: From d8f3d5b85c65322f84cbb3b1a93e5085fa432218 Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Sat, 28 Mar 2020 16:00:40 +0300 Subject: [PATCH 5/6] changed order of connections --- docs/en/Blog-Posts/2020-04-01/Post.md | 76 +++++++++++++-------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/docs/en/Blog-Posts/2020-04-01/Post.md b/docs/en/Blog-Posts/2020-04-01/Post.md index b57883ac8b..9f1d3d964b 100644 --- a/docs/en/Blog-Posts/2020-04-01/Post.md +++ b/docs/en/Blog-Posts/2020-04-01/Post.md @@ -8,10 +8,9 @@ Adding Azure Active Directory is pretty straightforward in Abp framework. Couple There will be two samples of connections for better covarage; -- **AddOpenIdConnect** (Default Microsoft.AspNetCore.Authentication.OpenIdConnect package) - **AddAzureAD** (Microsoft.AspNetCore.Authentication.AzureAD.UI package) - - +- **AddOpenIdConnect** (Default Microsoft.AspNetCore.Authentication.OpenIdConnect package) +- #### **Update your `appsettings.json`** @@ -29,38 +28,6 @@ In your **.Web** application, add the following section filled with your AzureAD -## AddOpenIdConnect - -Modify `ConfigureAuthentication` method of your **BookStoreWebModule** with the following: - -````xml -private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration) - { - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier); - - context.Services.AddAuthentication() - .AddIdentityServerAuthentication(options => - { - options.Authority = configuration["AuthServer:Authority"]; - options.RequireHttpsMetadata = false; - options.ApiName = "BookStore"; - }) - .AddOpenIdConnect("AzureOpenId", "AzureAD", options => - { - options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"]; - options.ClientId = configuration["AzureAd:ClientId"]; - options.ResponseType = OpenIdConnectResponseType.CodeIdToken; - options.CallbackPath = configuration["AzureAd:CallbackPath"]; - options.RequireHttpsMetadata = false; - options.SaveTokens = true; - options.GetClaimsFromUserInfoEndpoint = true; - }); - } -```` - - - ## AddAzureAD #### **Update your `appsettings.json`** @@ -103,11 +70,43 @@ private void ConfigureAuthentication(ServiceConfigurationContext context, IConfi +## AddOpenIdConnect + +Modify `ConfigureAuthentication` method of your **BookStoreWebModule** with the following: + +````xml +private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration) + { + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier); + + context.Services.AddAuthentication() + .AddIdentityServerAuthentication(options => + { + options.Authority = configuration["AuthServer:Authority"]; + options.RequireHttpsMetadata = false; + options.ApiName = "BookStore"; + }) + .AddOpenIdConnect("AzureOpenId", "AzureAD", options => + { + options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"]; + options.ClientId = configuration["AzureAd:ClientId"]; + options.ResponseType = OpenIdConnectResponseType.CodeIdToken; + options.CallbackPath = configuration["AzureAd:CallbackPath"]; + options.RequireHttpsMetadata = false; + options.SaveTokens = true; + options.GetClaimsFromUserInfoEndpoint = true; + }); + } +```` + + + # FAQ * Help! `GetExternalLoginInfoAsync` returns `null`! - * **There** can be 2 reasons for this; + * There can be 2 reasons for this; 1. You are trying to authenticate against wrong scheme. Check if you set **SignInScheme** to `IdentityConstants.ExternalScheme`: @@ -115,7 +114,7 @@ private void ConfigureAuthentication(ServiceConfigurationContext context, IConfi options.SignInScheme = IdentityConstants.ExternalScheme; ```` - 2. Your `ClaimTypes.NameIdentifier` is null. Check if you added claim mapping: + 2. Your `ClaimTypes.NameIdentifier` is `null`. Check if you added claim mapping: ````xml JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); @@ -169,5 +168,4 @@ private void ConfigureAuthentication(ServiceConfigurationContext context, IConfi * Why can't I see **External Register Page** after I sign in from external provider for the first time? - * ABP framework automatically registers your user with supported email claim from your external authentication provider. You can change this behaviour by [Customizing Login Page in Abp Framework](will be link here). - + * ABP framework automatically registers your user with supported email claim from your external authentication provider. You can change this behavior by [Customizing Login Page in Abp Framework](will be link here). From 01378dc04c37dd3eab4a0957f4410b627875c0b7 Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Sat, 28 Mar 2020 16:09:04 +0300 Subject: [PATCH 6/6] organized headers --- docs/en/Blog-Posts/2020-04-01/Post.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/en/Blog-Posts/2020-04-01/Post.md b/docs/en/Blog-Posts/2020-04-01/Post.md index 9f1d3d964b..2fb937467b 100644 --- a/docs/en/Blog-Posts/2020-04-01/Post.md +++ b/docs/en/Blog-Posts/2020-04-01/Post.md @@ -4,17 +4,24 @@ This post demonstrates how to integrate AzureAD to an ABP application that enables users to sign in using OAuth 2.0 with credentials from Azure Active Directory. -Adding Azure Active Directory is pretty straightforward in Abp framework. Couple of configurations needs to be done correctly. +Adding Azure Active Directory is pretty straightforward in ABP framework. Couple of configurations needs to be done correctly. -There will be two samples of connections for better covarage; +There will be two samples of connections for better coverage; - **AddAzureAD** (Microsoft.AspNetCore.Authentication.AzureAD.UI package) - **AddOpenIdConnect** (Default Microsoft.AspNetCore.Authentication.OpenIdConnect package) -- -#### **Update your `appsettings.json`** -In your **.Web** application, add the following section filled with your AzureAD application settings. + +## Sample Code + +https://github.com/abpframework/abp-samples/tree/master/aspnet-core/BookStore-AzureAD + + + +## Setup + +Update your `appsettings.json` in your **.Web** application and add the following section filled with your AzureAD application settings. ````xml "AzureAd": {