Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
84 lines (75 sloc) 3.72 KB
// Copyright (c) 2018 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
// Licensed under MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using DataAuthorize;
using DataKeyParts;
using DataLayer.EfCode;
using FeatureAuthorize;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.DependencyInjection;
using RefreshClaimsParts;
namespace AuthorizeSetup
{
/// <summary>
/// This version provides:
/// - Adds Permissions to the user's claims.
/// - Adds DataKey to the user's claims
/// - AND the user's claims are updated if there is a change in the roles/datakey information
/// </summary>
public class AuthCookieValidateRefreshClaims : IAuthCookieValidate
{
public async Task ValidateAsync(CookieValidatePrincipalContext context)
{
var authChanges = new AuthChanges();
var extraContext = context.HttpContext.RequestServices.GetRequiredService<ExtraAuthorizeDbContext>();
var newClaims = new List<Claim>();
var originalClaims = context.Principal.Claims.ToList();
if (originalClaims.All(x => x.Type != PermissionConstants.PackedPermissionClaimType) ||
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 userId = originalClaims.GetUserIdFromClaims();
newClaims.AddRange(await BuildFeatureClaimsAsync(userId, rtoPCalcer));
newClaims.AddRange(BuildDataClaims(userId, dataKeyCalc));
//Something has changed so we replace the current ClaimsPrincipal with a new one
newClaims.AddRange(RemoveUpdatedClaimsFromOriginalClaims(originalClaims, newClaims)); //Copy over unchanged claims
//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;
}
}
private IEnumerable<Claim> RemoveUpdatedClaimsFromOriginalClaims(List<Claim> originalClaims, List<Claim> newClaims)
{
var newClaimTypes = newClaims.Select(x => x.Type);
return originalClaims.Where(x => !newClaimTypes.Contains(x.Type));
}
private async Task<List<Claim>> BuildFeatureClaimsAsync(string userId, CalcAllowedPermissions rtoP)
{
var claims = new List<Claim>
{
new Claim(PermissionConstants.PackedPermissionClaimType, await rtoP.CalcPermissionsForUserAsync(userId)),
new Claim(PermissionConstants.LastPermissionsUpdatedClaimType, DateTime.UtcNow.Ticks.ToString())
};
return claims;
}
private List<Claim> BuildDataClaims(string userId, CalcDataKey dataKeyCalc)
{
var claims = new List<Claim>
{
new Claim(DataAuthConstants.HierarchicalKeyClaimName, dataKeyCalc.CalcDataKeyForUser(userId))
};
return claims;
}
}
}
You can’t perform that action at this time.