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.
        }
Пример #3
0
        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);
        }
Пример #5
0
        /// <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;
            }
        }
Пример #6
0
        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("*****@*****.**");
        }