public async Task ValidateAsync(CookieValidatePrincipalContext context) { var originalClaims = context.Principal.Claims.ToList(); var protectionProvider = context.HttpContext.RequestServices.GetService <IDataProtectionProvider>(); var impHandler = new ImpersonationHandler(context.HttpContext, protectionProvider, originalClaims); var newClaims = new List <Claim>(); if (originalClaims.All(x => x.Type != PermissionConstants.PackedPermissionClaimType) || impHandler.ImpersonationChange) { //There is no PackedPermissionClaimType or there was a change in the impersonation state var extraContext = context.HttpContext.RequestServices.GetRequiredService <ExtraAuthorizeDbContext>(); var rtoPCalcer = new CalcAllowedPermissions(extraContext); var dataKeyCalc = new CalcDataKey(extraContext); var userId = impHandler.GetUserIdForWorkingDataKey(); newClaims.AddRange(await BuildFeatureClaimsAsync(userId, rtoPCalcer)); newClaims.AddRange(BuildDataClaims(userId, dataKeyCalc)); newClaims.AddRange(RemoveUpdatedClaimsFromOriginalClaims(originalClaims, newClaims)); //Copy over unchanged claims impHandler.AddOrRemoveImpersonationClaim(newClaims); //Build a new ClaimsPrincipal and use it to replace the current ClaimsPrincipal var identity = new ClaimsIdentity(newClaims, "Cookie"); var newPrincipal = new ClaimsPrincipal(identity); context.ReplacePrincipal(newPrincipal); //THIS IS IMPORTANT: This updates the cookie, otherwise this calc will be done every HTTP request context.ShouldRenew = true; } }
/// <summary> /// This will set up the user's feature permissions if either of the following states are found /// - The current claims doesn't have the PackedPermissionClaimType. This happens when someone logs in. /// - If the LastPermissionsUpdatedClaimType is missing (null) or is a lower number that is stored in the TimeStore cache. /// It will also add a HierarchicalKeyClaimName claim with the user's data key if not present. /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task ValidateAsync(CookieValidatePrincipalContext context) { var extraContext = new ExtraAuthorizeDbContext(_extraAuthContextOptions, _authChanges); //now we set up the lazy values - I used Lazy for performance reasons, as 99.9% of the time the lazy parts aren't needed // ReSharper disable once AccessToDisposedClosure var rtoPLazy = new Lazy <CalcAllowedPermissions>(() => new CalcAllowedPermissions(extraContext)); // ReSharper disable once AccessToDisposedClosure var dataKeyLazy = new Lazy <CalcDataKey>(() => new CalcDataKey(extraContext)); var originalClaims = context.Principal.Claims.ToList(); var impHandler = new ImpersonationHandler(context.HttpContext, _protectionProvider, originalClaims); var newClaims = new List <Claim>(); if (originalClaims.All(x => x.Type != PermissionConstants.PackedPermissionClaimType) || impHandler.ImpersonationChange || _authChanges.IsOutOfDateOrMissing(AuthChangesConsts.FeatureCacheKey, originalClaims.SingleOrDefault(x => x.Type == PermissionConstants.LastPermissionsUpdatedClaimType)?.Value, extraContext)) { //Handle the feature permissions var userId = impHandler.GetUserIdForWorkingOutPermissions(); newClaims.AddRange(await BuildFeatureClaimsAsync(userId, rtoPLazy.Value)); } if (originalClaims.All(x => x.Type != DataAuthConstants.HierarchicalKeyClaimName) || impHandler.ImpersonationChange) { var userId = impHandler.GetUserIdForWorkingDataKey(); newClaims.AddRange(BuildDataClaims(userId, dataKeyLazy.Value)); } if (newClaims.Any()) { //Something has changed so we replace the current ClaimsPrincipal with a new one newClaims.AddRange(RemoveUpdatedClaimsFromOriginalClaims(originalClaims, newClaims)); //Copy over unchanged claims impHandler.AddOrRemoveImpersonationClaim(newClaims); //Build a new ClaimsPrincipal and use it to replace the current ClaimsPrincipal var identity = new ClaimsIdentity(newClaims, "Cookie"); var newPrincipal = new ClaimsPrincipal(identity); context.ReplacePrincipal(newPrincipal); //THIS IS IMPORTANT: This updates the cookie, otherwise this calc will be done every HTTP request context.ShouldRenew = true; } extraContext.Dispose(); //be tidy and dispose the context. }
public void TestHandlerNoCookieNoClaim() { //SETUP var mocks = new MockHttpContextCookies(); var eProvider = new EphemeralDataProtectionProvider(); var claims = new List <Claim> { new Claim(ClaimTypes.NameIdentifier, "userid") }; //ATTEMPT var handler = new ImpersonationHandler(mocks.MockContext, eProvider, claims); //VERIFY handler.ImpersonationChange.ShouldBeFalse(); handler.GetUserIdForWorkingOutPermissions().ShouldEqual("userid"); handler.GetUserIdForWorkingDataKey().ShouldEqual("userid"); handler.AddOrRemoveImpersonationClaim(claims); claims.Count.ShouldEqual(1); }
public void TestHandlerStopping() { //SETUP var httpContext = new DefaultHttpContext(); var eProvider = new EphemeralDataProtectionProvider(); var claims = new List <Claim> { new Claim(ClaimTypes.NameIdentifier, "userid"), new Claim(ImpersonationHandler.ImpersonationClaimType, "*****@*****.**") }; //ATTEMPT var handler = new ImpersonationHandler(httpContext, eProvider, claims); //VERIFY handler.ImpersonationChange.ShouldBeTrue(); handler.GetUserIdForWorkingOutPermissions().ShouldEqual("userid"); handler.GetUserIdForWorkingDataKey().ShouldEqual("userid"); handler.AddOrRemoveImpersonationClaim(claims); claims.Count.ShouldEqual(1); }
/// <summary> /// This will set up the user's feature permissions if either of the following states are found /// - The current claims doesn't have the PackedPermissionClaimType. This happens when someone logs in. /// - If the LastPermissionsUpdatedClaimType is missing (null) or is a lower number that is stored in the TimeStore cache. /// It will also add a HierarchicalKeyClaimName claim with the user's data key if not present. /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task ValidateAsync(CookieValidatePrincipalContext context) { var extraContext = context.HttpContext.RequestServices.GetRequiredService <ExtraAuthorizeDbContext>(); var protectionProvider = context.HttpContext.RequestServices.GetService <IDataProtectionProvider>(); var authChanges = new AuthChanges(); var originalClaims = context.Principal.Claims.ToList(); var impHandler = new ImpersonationHandler(context.HttpContext, protectionProvider, originalClaims); var newClaims = new List <Claim>(); if (originalClaims.All(x => x.Type != PermissionConstants.PackedPermissionClaimType) || impHandler.ImpersonationChange || authChanges.IsOutOfDateOrMissing(AuthChangesConsts.FeatureCacheKey, originalClaims.SingleOrDefault(x => x.Type == PermissionConstants.LastPermissionsUpdatedClaimType)?.Value, extraContext)) { var rtoPCalcer = new CalcAllowedPermissions(extraContext); var dataKeyCalc = new CalcDataKey(extraContext); //Handle the feature permissions var permissionUserId = impHandler.GetUserIdForWorkingOutPermissions(); newClaims.AddRange(await BuildFeatureClaimsAsync(permissionUserId, rtoPCalcer)); //Handle the DataKey var datakeyUserId = impHandler.GetUserIdForWorkingDataKey(); newClaims.AddRange(BuildDataClaims(datakeyUserId, dataKeyCalc)); //Something has changed so we replace the current ClaimsPrincipal with a new one newClaims.AddRange(RemoveUpdatedClaimsFromOriginalClaims(originalClaims, newClaims)); //Copy over unchanged claims impHandler.AddOrRemoveImpersonationClaim(newClaims); //Build a new ClaimsPrincipal and use it to replace the current ClaimsPrincipal var identity = new ClaimsIdentity(newClaims, "Cookie"); var newPrincipal = new ClaimsPrincipal(identity); context.ReplacePrincipal(newPrincipal); //THIS IS IMPORTANT: This updates the cookie, otherwise this calc will be done every HTTP request context.ShouldRenew = true; } }
public void TestHandlerStartingKeepOwnPermissions() { //SETUP var mocks = new MockHttpContextCookies(); var eProvider = new EphemeralDataProtectionProvider(); AddCookieToHttpContext(mocks, eProvider, true); var claims = new List <Claim> { new Claim(ClaimTypes.NameIdentifier, "userid") }; //ATTEMPT var handler = new ImpersonationHandler(mocks.MockContext, eProvider, claims); //VERIFY handler.ImpersonationChange.ShouldBeTrue(); handler.GetUserIdForWorkingOutPermissions().ShouldEqual("userid"); handler.GetUserIdForWorkingDataKey().ShouldEqual("differentUserId"); handler.AddOrRemoveImpersonationClaim(claims); claims.SingleOrDefault(x => x.Type == ImpersonationHandler.ImpersonationClaimType)?.Value.ShouldEqual("*****@*****.**"); }