From a38faf84e73dac7808d0086965f8f3082ab66357 Mon Sep 17 00:00:00 2001 From: pmaytak <34331512+pmaytak@users.noreply.github.com> Date: Wed, 8 Jul 2020 22:50:49 -0700 Subject: [PATCH 1/4] Update TodoList-WebApi.csproj --- 2-Call-OwnApi/TodoList-WebApi/TodoList-WebApi.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2-Call-OwnApi/TodoList-WebApi/TodoList-WebApi.csproj b/2-Call-OwnApi/TodoList-WebApi/TodoList-WebApi.csproj index d4d1f4a..21ef9f1 100644 --- a/2-Call-OwnApi/TodoList-WebApi/TodoList-WebApi.csproj +++ b/2-Call-OwnApi/TodoList-WebApi/TodoList-WebApi.csproj @@ -8,7 +8,7 @@ - + From 05471102388b5c953ef7c7d6b0f0c9f580414317 Mon Sep 17 00:00:00 2001 From: pmaytak <34331512+pmaytak@users.noreply.github.com> Date: Wed, 8 Jul 2020 23:12:13 -0700 Subject: [PATCH 2/4] Update README.md --- 2-Call-OwnApi/README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/2-Call-OwnApi/README.md b/2-Call-OwnApi/README.md index 291a7be..d409f3c 100644 --- a/2-Call-OwnApi/README.md +++ b/2-Call-OwnApi/README.md @@ -265,7 +265,7 @@ The relevant code for this sample is in the `Program.cs` file, in the `RunAsync( ### TodoList Web API Code -The relevant code for the Web API is on the `Startup.cs` class. We are using the method `AddProtectWebApiWithMicrosoftIdentityPlatformV2` to configure the Web API to authenticate using bearer tokens, validate them and protect the API from non authorized calls. These are the steps: +The relevant code for the Web API is on the `Startup.cs` class. We are using the method `AddMicrosoftWebApiAuthentication` to configure the Web API to authenticate using bearer tokens, validate them and protect the API from non authorized calls. These are the steps: 1. Configuring the API to authenticate using bearer tokens @@ -274,20 +274,17 @@ The relevant code for the Web API is on the `Startup.cs` class. We are using the // 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role' instead of 'roles' JwtSecurityTokenHandler.DefaultMapInboundClaims = false; - services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme) - .AddAzureADBearer(options => configuration.Bind("AzureAd", options)); + services.AddMicrosoftWebApiAuthentication(Configuration); - services.Configure(AzureADDefaults.JwtBearerAuthenticationScheme, options => + services.Configure(JwtBearerDefaults.AuthenticationScheme, options => { - configuration.Bind("AzureAd", options); - options.Authority += "/v2.0"; options.TokenValidationParameters.RoleClaimType = "roles"; }); ``` 2. Validating the tokens - The `AadIssuerValidator.GetIssuerValidator` method can be found on `Microsoft.Identity.Web` project. + The `AadIssuerValidator.GetIssuerValidator` method can be found in `Microsoft.Identity.Web` project. ```CSharp options.TokenValidationParameters.ValidAudiences = new string[] { options.Audience, $"api://{options.Audience}" }; @@ -299,16 +296,19 @@ The relevant code for the Web API is on the `Startup.cs` class. We are using the Only apps that have added the **application role** created on **Azure Portal** for the `TodoList-webapi-daemon-v2`, will contain the claim `roles` on their tokens ```CSharp + var tokenValidatedHandler = options.Events.OnTokenValidated; options.Events.OnTokenValidated = async context => { // This check is required to ensure that the Web API only accepts tokens from tenants where it has been consented and provisioned. if (!context.Principal.Claims.Any(x => x.Type == ClaimConstants.Scope) - && !context.Principal.Claims.Any(y => y.Type == ClaimConstants.Roles)) + && !context.Principal.Claims.Any(y => y.Type == ClaimConstants.Scp) + && !context.Principal.Claims.Any(y => y.Type == ClaimConstants.Roles) + && !context.Principal.Claims.Any(y => y.Type == ClaimConstants.Role)) { - throw new UnauthorizedAccessException("Neither scope or roles claim were found in the bearer token."); + throw new UnauthorizedAccessException(ErrorMessage.NeitherScopeOrRolesClaimFoundInToken); } - await Task.FromResult(0); + await tokenValidatedHandler(context).ConfigureAwait(false); }; ``` From 4cc8e813f705e35e2a79806ba0c7003e14df5b65 Mon Sep 17 00:00:00 2001 From: pmaytak <34331512+pmaytak@users.noreply.github.com> Date: Thu, 9 Jul 2020 12:16:21 -0700 Subject: [PATCH 3/4] Update README.md --- 2-Call-OwnApi/README.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/2-Call-OwnApi/README.md b/2-Call-OwnApi/README.md index d409f3c..1da47ca 100644 --- a/2-Call-OwnApi/README.md +++ b/2-Call-OwnApi/README.md @@ -265,7 +265,7 @@ The relevant code for this sample is in the `Program.cs` file, in the `RunAsync( ### TodoList Web API Code -The relevant code for the Web API is on the `Startup.cs` class. We are using the method `AddMicrosoftWebApiAuthentication` to configure the Web API to authenticate using bearer tokens, validate them and protect the API from non authorized calls. These are the steps: +The relevant code for the Web API is in the `Startup.cs` class. We are using the method `AddMicrosoftWebApiAuthentication` to configure the Web API to authenticate using bearer tokens, validate them and protect the API from non authorized calls. These are the steps: 1. Configuring the API to authenticate using bearer tokens @@ -284,11 +284,26 @@ The relevant code for the Web API is on the `Startup.cs` class. We are using the 2. Validating the tokens - The `AadIssuerValidator.GetIssuerValidator` method can be found in `Microsoft.Identity.Web` project. + As a result of the above `AddMicrosoftWebApiAuthentication` method, some audience and issuer validation is set up. More information can be found in [Microsoft Identity Web](https://github.com/AzureAD/microsoft-identity-web) project. ```CSharp - options.TokenValidationParameters.ValidAudiences = new string[] { options.Audience, $"api://{options.Audience}" }; - options.TokenValidationParameters.IssuerValidator = AadIssuerValidator.GetIssuerValidator(options.Authority).Validate; + if (options.TokenValidationParameters.AudienceValidator == null + && options.TokenValidationParameters.ValidAudience == null + && options.TokenValidationParameters.ValidAudiences == null) + { + RegisterValidAudience registerAudience = new RegisterValidAudience(); + registerAudience.RegisterAudienceValidation( + options.TokenValidationParameters, + microsoftIdentityOptions.Value); + } + + // If the developer registered an IssuerValidator, do not overwrite it + if (options.TokenValidationParameters.IssuerValidator == null) + { + // Instead of using the default validation (validating against a single tenant, as we do in line of business apps), + // we inject our own multi-tenant validation logic (which even accepts both v1.0 and v2.0 tokens) + options.TokenValidationParameters.IssuerValidator = AadIssuerValidator.GetIssuerValidator(options.Authority).Validate; + } ``` 3. Protecting the Web API From 48f60e28ba6374a7eba6ccc626ba65cda7ba3fba Mon Sep 17 00:00:00 2001 From: pmaytak <34331512+pmaytak@users.noreply.github.com> Date: Thu, 9 Jul 2020 15:02:35 -0700 Subject: [PATCH 4/4] Update README.md --- 2-Call-OwnApi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2-Call-OwnApi/README.md b/2-Call-OwnApi/README.md index 1da47ca..1bd1ef2 100644 --- a/2-Call-OwnApi/README.md +++ b/2-Call-OwnApi/README.md @@ -320,7 +320,7 @@ The relevant code for the Web API is in the `Startup.cs` class. We are using the && !context.Principal.Claims.Any(y => y.Type == ClaimConstants.Roles) && !context.Principal.Claims.Any(y => y.Type == ClaimConstants.Role)) { - throw new UnauthorizedAccessException(ErrorMessage.NeitherScopeOrRolesClaimFoundInToken); + throw new UnauthorizedAccessException("Neither scope or roles claim were found in the bearer token."); } await tokenValidatedHandler(context).ConfigureAwait(false);