From ed6992657abe9f455e4a95e64be95d983581b9ff Mon Sep 17 00:00:00 2001 From: damienbod Date: Sat, 2 Dec 2023 11:50:36 +0100 Subject: [PATCH] Update setup --- ...essionCookieWhenAccountNotInCacheEvents.cs | 37 +++++++++++++++++++ IssueVerifiableEmployee/Startup.cs | 12 +++++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 IssueVerifiableEmployee/RejectSessionCookieWhenAccountNotInCacheEvents.cs diff --git a/IssueVerifiableEmployee/RejectSessionCookieWhenAccountNotInCacheEvents.cs b/IssueVerifiableEmployee/RejectSessionCookieWhenAccountNotInCacheEvents.cs new file mode 100644 index 0000000..98e6b7c --- /dev/null +++ b/IssueVerifiableEmployee/RejectSessionCookieWhenAccountNotInCacheEvents.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.Identity.Client; +using Microsoft.Identity.Web; + +namespace BffMicrosoftEntraID.Server; + +public class RejectSessionCookieWhenAccountNotInCacheEvents : CookieAuthenticationEvents +{ + private readonly string[] _downstreamScopes; + + public RejectSessionCookieWhenAccountNotInCacheEvents(string[] downstreamScopes) + { + _downstreamScopes = downstreamScopes; + } + + public async override Task ValidatePrincipal(CookieValidatePrincipalContext context) + { + try + { + var tokenAcquisition = context.HttpContext.RequestServices + .GetRequiredService(); + + string token = await tokenAcquisition.GetAccessTokenForUserAsync(scopes: _downstreamScopes, + user: context.Principal); + } + catch (MicrosoftIdentityWebChallengeUserException ex) when (AccountDoesNotExitInTokenCache(ex)) + { + context.RejectPrincipal(); + } + } + + private static bool AccountDoesNotExitInTokenCache(MicrosoftIdentityWebChallengeUserException ex) + { + return ex.InnerException is MsalUiRequiredException + && (ex.InnerException as MsalUiRequiredException)!.ErrorCode == "user_null"; + } +} diff --git a/IssueVerifiableEmployee/Startup.cs b/IssueVerifiableEmployee/Startup.cs index 74a3230..adf2c6e 100644 --- a/IssueVerifiableEmployee/Startup.cs +++ b/IssueVerifiableEmployee/Startup.cs @@ -1,4 +1,6 @@ +using BffMicrosoftEntraID.Server; using IssuerVerifiableEmployee.Services.GraphServices; +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Identity.Web; @@ -28,12 +30,20 @@ public void ConfigureServices(IServiceCollection services) services.AddDistributedMemoryCache(); + var scopes = new string[] { "user.read" }; services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd")) - .EnableTokenAcquisitionToCallDownstreamApi(new string[] { "user.read"}) + .EnableTokenAcquisitionToCallDownstreamApi(scopes) .AddMicrosoftGraph() .AddDistributedTokenCaches(); + // If using downstream APIs and in memory cache, you need to reset the cookie session if the cache is missing + // If you use persistent cache, you do not require this. + // You can also return the 403 with the required scopes, this needs special handling for ajax calls + // The check is only for single scopes + services.Configure(CookieAuthenticationDefaults.AuthenticationScheme, + options => options.Events = new RejectSessionCookieWhenAccountNotInCacheEvents(scopes)); + services.AddAuthorization(options => { options.FallbackPolicy = options.DefaultPolicy;