be7ee4cae8
feature: flag permissions
403 lines
14 KiB
Plaintext
403 lines
14 KiB
Plaintext
<#@ template language="C#" debug="true" hostspecific="true" #>
|
|
<#@ output extension=".cs" #>
|
|
<#@ assembly name="System.Core" #>
|
|
<#@ assembly name="Microsoft.VisualStudio.Shell.Interop" #>
|
|
<#@ assembly name="EnvDTE" #>
|
|
<#@ assembly name="EnvDTE80" #>
|
|
<#@ assembly name="VSLangProj" #>
|
|
<#@ assembly name="System.Xml" #>
|
|
<#@ assembly name="System.Xml.Linq" #>
|
|
<#@ assembly name="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\CustomMarshalers.dll" #>
|
|
<#@ import namespace="System.Collections.Generic" #>
|
|
<#@ import namespace="System.IO" #>
|
|
<#@ import namespace="System.Linq" #>
|
|
<#@ import namespace="System.Text" #>
|
|
<#@ import namespace="System.Text.RegularExpressions" #>
|
|
<#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
|
|
<#@ import namespace="EnvDTE" #>
|
|
<#@ import namespace="EnvDTE80" #>
|
|
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
|
|
<#@ import namespace="System.Runtime.InteropServices.CustomMarshalers" #>
|
|
<#@ import namespace="System.Runtime.InteropServices" #>
|
|
<#@ import namespace="System.Reflection" #>
|
|
<#
|
|
// Get the DTE service from the host
|
|
EnvDTE.DTE Dte = null;
|
|
var serviceProvider = Host as IServiceProvider;
|
|
if (serviceProvider != null)
|
|
Dte = (EnvDTE.DTE)serviceProvider.GetService(typeof(EnvDTE.DTE));
|
|
|
|
// Fail if we couldn't get the DTE. This can happen when trying to run in TextTransform.exe
|
|
if (Dte == null)
|
|
throw new Exception("T4MVC can only execute through the Visual Studio host");
|
|
|
|
List<Permission> permissions = new List<Permission>();
|
|
List<Permission> groups = new List<Permission>();
|
|
|
|
var piRolePermission = Dte.Solution.FindProjectItem(Host.ResolvePath(@"Roles\RoleClaims.cs"));
|
|
var piGroups = FindClaimGroupProjectItems(piRolePermission.ContainingProject.ProjectItems.Item("Authorization").ProjectItems.Item("Roles").ProjectItems.Item("ClaimGroups")).ToList();
|
|
|
|
ParseProjectItem(piRolePermission, groups, permissions);
|
|
foreach (ProjectItem piItem in piGroups)
|
|
ParseProjectItem(piItem, groups, permissions);
|
|
|
|
var permissionRoot = BuildHierarchy(groups, permissions);
|
|
|
|
|
|
|
|
#>
|
|
// <auto-generated />
|
|
// This file was generated by a T4 template.
|
|
// Don't change it directly as your change would get overwritten. Instead, make changes
|
|
// to the .tt file (i.e. the T4 template) and save it to regenerate this file.
|
|
using Disco.Models.Services.Authorization;
|
|
using Disco.Models.Repository;
|
|
using Disco.Services.Authorization.Roles;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Disco.Services.Authorization
|
|
{
|
|
public static class Claims
|
|
{
|
|
private static Dictionary<string, Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>> _roleClaims;
|
|
private static ClaimNavigatorItem _claimNavigator;
|
|
|
|
static Claims()
|
|
{
|
|
#region Role Claim Dictionary
|
|
_roleClaims = new Dictionary<string, Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>>()
|
|
{
|
|
<#WriteAccessHashes(permissionRoot);#>
|
|
};
|
|
#endregion
|
|
|
|
#region Role Claim Navigator
|
|
_claimNavigator =
|
|
<#WriteNavigator(permissionRoot);#>;
|
|
#endregion
|
|
}
|
|
|
|
public static ClaimNavigatorItem RoleClaimNavigator
|
|
{
|
|
get { return _claimNavigator; }
|
|
}
|
|
|
|
internal static Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool> GetClaimDefinition(string ClaimKey)
|
|
{
|
|
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
|
|
return claimDef;
|
|
throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey));
|
|
}
|
|
|
|
public static Func<RoleClaims, bool> GetClaimAccessor(string ClaimKey)
|
|
{
|
|
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
|
|
return claimDef.Item1;
|
|
throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey));
|
|
}
|
|
|
|
public static Action<RoleClaims, bool> GetClaimSetter(string ClaimKey)
|
|
{
|
|
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
|
|
return claimDef.Item2;
|
|
throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey));
|
|
}
|
|
|
|
public static Tuple<string, string, bool> GetClaimDetails(string ClaimKey)
|
|
{
|
|
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
|
|
return Tuple.Create(claimDef.Item3, claimDef.Item4, claimDef.Item5);
|
|
throw new ArgumentException("Unknown Claim Key", "ClaimKey");
|
|
}
|
|
|
|
public static RoleClaims BuildClaims(IEnumerable<string> ClaimKeys)
|
|
{
|
|
var c = new RoleClaims();
|
|
foreach (var claimKey in ClaimKeys)
|
|
c.Set(claimKey, true);
|
|
|
|
return c;
|
|
}
|
|
|
|
public static List<string> GetClaimKeys(RoleClaims Claims)
|
|
{
|
|
var claims = Claims;
|
|
return _roleClaims.Where(rc => rc.Value.Item1(claims)).Select(rc => rc.Key).ToList();
|
|
}
|
|
|
|
public static RoleClaims AdministratorClaims()
|
|
{
|
|
var c = new RoleClaims();
|
|
#region Set All Administrator Claims
|
|
<#WriteAdministratorClaims(permissionRoot);#>
|
|
#endregion
|
|
return c;
|
|
}
|
|
|
|
public static RoleClaims ComputerAccountClaims()
|
|
{
|
|
return new RoleClaims()
|
|
{
|
|
ComputerAccount = true
|
|
};
|
|
}
|
|
|
|
#region Role Claim Constants
|
|
<#WritePermissionConsts(permissionRoot);#>
|
|
#endregion
|
|
}
|
|
public static class ClaimExtensions
|
|
{
|
|
public static bool Has(this RoleClaims c, string ClaimKey)
|
|
{
|
|
Func<RoleClaims, bool> claimFunc = Claims.GetClaimAccessor(ClaimKey);
|
|
|
|
return claimFunc(c);
|
|
}
|
|
|
|
public static void Set(this RoleClaims c, string ClaimKey, bool Value)
|
|
{
|
|
var claimDefinition = Claims.GetClaimDefinition(ClaimKey);
|
|
|
|
if (!claimDefinition.Item5)
|
|
claimDefinition.Item2(c, Value);
|
|
}
|
|
|
|
public static void SetClaims(this AuthorizationRole role, RoleClaims Claims)
|
|
{
|
|
role.ClaimsJson = Newtonsoft.Json.JsonConvert.SerializeObject(Claims);
|
|
}
|
|
}
|
|
}
|
|
<#+
|
|
|
|
void DumpPermission(Permission p){
|
|
PushIndent(" ");
|
|
WriteLine(p.Name);
|
|
foreach (Permission pChild in p.Children)
|
|
{
|
|
DumpPermission(pChild);
|
|
}
|
|
PopIndent();
|
|
}
|
|
|
|
void WriteNavigator(Permission root){
|
|
PushIndent(" ");
|
|
WriteLine("new ClaimNavigatorItem(\"Claims\", \"Permissions\", \"Top-level node for all permissions\", false, new List<IClaimNavigatorItem>() {");
|
|
PushIndent(" ");
|
|
for (int childIndex = 0; childIndex < root.Children.Count; childIndex++)
|
|
{
|
|
WriteNavigator_Recurse(root.Children[childIndex], string.Empty);
|
|
if (childIndex < root.Children.Count -1)
|
|
WriteLine(",");
|
|
}
|
|
WriteLine(string.Empty);
|
|
PopIndent();
|
|
Write("})");
|
|
PopIndent();
|
|
}
|
|
|
|
void WriteNavigator_Recurse(Permission p, string Prefix){
|
|
var key = string.Concat(Prefix, p.Name);
|
|
|
|
if (p.IsGroup){
|
|
var groupPrefix = string.Concat(key, ".");
|
|
WriteLine("new ClaimNavigatorItem(\"{0}{1}\", \"{2}\", \"{3}\", {4}, new List<IClaimNavigatorItem>() {{", Prefix, p.Name, p.FriendlyName, p.Description, p.Hidden ? "true" : "false");
|
|
PushIndent(" ");
|
|
var children = p.Children.OrderBy(c => !c.IsGroup).ThenBy(c => c.FriendlyName).ToList();
|
|
for (int childIndex = 0; childIndex < children.Count; childIndex++)
|
|
{
|
|
WriteNavigator_Recurse(children[childIndex], groupPrefix);
|
|
if (childIndex < children.Count -1)
|
|
WriteLine(",");
|
|
else
|
|
WriteLine(string.Empty);
|
|
}
|
|
PopIndent();
|
|
Write("})");
|
|
}else{
|
|
Write("new ClaimNavigatorItem(\"{0}{1}\", {2})", Prefix, p.Name, p.Hidden ? "true" : "false");
|
|
}
|
|
}
|
|
|
|
void WriteAdministratorClaims(Permission root){
|
|
PushIndent(" ");
|
|
Stack<string> parents = new Stack<string>();
|
|
parents.Push("c");
|
|
foreach (var pChild in root.Children)
|
|
WriteAdministratorClaims_Recurse(pChild, parents);
|
|
PopIndent();
|
|
}
|
|
|
|
void WriteAdministratorClaims_Recurse(Permission p, Stack<string> parents){
|
|
if (p.IsGroup){
|
|
parents.Push(string.Format("{0}.{1}", parents.Peek(), p.Name));
|
|
foreach (var pChild in p.Children)
|
|
WriteAdministratorClaims_Recurse(pChild, parents);
|
|
parents.Pop();
|
|
}else{
|
|
if (p.Name != "ComputerAccount")
|
|
WriteLine("{0}.{1} = true;", parents.Peek(), p.Name);
|
|
}
|
|
}
|
|
|
|
|
|
void WriteAccessHashes(Permission root){
|
|
StringBuilder hashes = new StringBuilder();
|
|
Stack<string> parents = new Stack<string>();
|
|
parents.Push("c");
|
|
foreach (var pChild in root.Children)
|
|
WriteAccessHashes_Recurse(pChild, string.Empty, parents, hashes);
|
|
WriteLine(hashes.ToString().TrimEnd().TrimEnd(','));
|
|
}
|
|
|
|
void WriteAccessHashes_Recurse(Permission p, string Prefix, Stack<string> parents, StringBuilder hashes){
|
|
if (p.IsGroup){
|
|
parents.Push(string.Format("{0}.{1}", parents.Peek(), p.Name));
|
|
foreach (var pChild in p.Children)
|
|
WriteAccessHashes_Recurse(pChild, string.Concat(Prefix, p.Name, "."), parents, hashes);
|
|
parents.Pop();
|
|
}else{
|
|
var fqn = string.Concat(Prefix, p.Name);
|
|
hashes.AppendFormat(" {{ \"{0}\", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => {1}.{2}, (c, v) => {1}.{2} = v, \"{3}\", \"{4}\", {5}) }},", fqn, parents.Peek(), p.Name, p.FriendlyName, p.Description, p.Hidden ? "true" : "false");
|
|
hashes.AppendLine();
|
|
}
|
|
}
|
|
|
|
void WritePermissionConsts(Permission root){
|
|
PushIndent(" ");
|
|
PushIndent(" ");
|
|
foreach (var pChild in root.Children)
|
|
WritePermissionConsts_Recurse(pChild, string.Empty);
|
|
PopIndent();
|
|
PopIndent();
|
|
}
|
|
void WritePermissionConsts_Recurse(Permission p, string Prefix){
|
|
if (p.IsGroup){
|
|
WriteLine("");
|
|
WriteLine("/// <summary>{0}", p.FriendlyName);
|
|
WriteLine("/// <para>{0}</para>", p.Description);
|
|
WriteLine("/// </summary>");
|
|
WriteLine("public static class {0}", p.Name);
|
|
WriteLine("{");
|
|
PushIndent(" ");
|
|
foreach (var pChild in p.Children)
|
|
WritePermissionConsts_Recurse(pChild, string.Concat(Prefix, p.Name, "."));
|
|
PopIndent();
|
|
WriteLine("}");
|
|
}else{
|
|
WriteLine("");
|
|
WriteLine("/// <summary>{0}", p.FriendlyName);
|
|
WriteLine("/// <para>{0}</para>", p.Description);
|
|
WriteLine("/// </summary>");
|
|
WriteLine("public const string {0} = \"{1}{0}\";", p.Name, Prefix);
|
|
}
|
|
}
|
|
|
|
Permission BuildHierarchy(List<Permission> groups, List<Permission> permissions){
|
|
var top = groups[0];
|
|
|
|
// Find Parents
|
|
var groupDict = groups.ToDictionary(p => p.FullName);
|
|
|
|
// Hierarchy
|
|
foreach (var p in permissions.Where(p => p.IsGroup))
|
|
{
|
|
var g = groupDict[p.Type];
|
|
p.Children = g.Children;
|
|
p.FriendlyName = g.FriendlyName;
|
|
p.Description = g.Description;
|
|
}
|
|
|
|
return top;
|
|
}
|
|
|
|
void ParseProjectItem(ProjectItem item, List<Permission> groups, List<Permission> permissions){
|
|
foreach (var ns in item.FileCodeModel.CodeElements.OfType<CodeNamespace>())
|
|
{
|
|
foreach (var cl in ns.Members.OfType<CodeClass2>())
|
|
{
|
|
var g = BuildPermission(cl);
|
|
groups.Add(g);
|
|
foreach (var pr in cl.Members.OfType<CodeProperty2>())
|
|
{
|
|
var p = BuildPermission(pr);
|
|
permissions.Add(p);
|
|
g.Children.Add(p);
|
|
}
|
|
g.Children = g.Children.OrderBy(p => p.IsGroup).OrderBy(p => p.FriendlyName).ToList();
|
|
}
|
|
}
|
|
}
|
|
|
|
IEnumerable<ProjectItem> FindClaimGroupProjectItems(ProjectItem item){
|
|
const string collectionGuid = "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}";
|
|
|
|
if (item.Kind == collectionGuid)
|
|
foreach (ProjectItem subItem in item.ProjectItems)
|
|
foreach (var returnItem in FindClaimGroupProjectItems(subItem))
|
|
yield return returnItem;
|
|
else
|
|
yield return item;
|
|
}
|
|
|
|
Permission BuildPermission(CodeClass2 item){
|
|
return new Permission(item.FullName, item.Name, item.FullName, item.Attributes);
|
|
}
|
|
|
|
Permission BuildPermission(CodeProperty2 item){
|
|
return new Permission(item.FullName, item.Name, item.Type.AsFullName, item.Attributes);
|
|
}
|
|
|
|
[ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
public interface IDispatch
|
|
{
|
|
void Reserved();
|
|
[PreserveSig]
|
|
int GetTypeInfo(uint nInfo, int lcid,
|
|
[MarshalAs(
|
|
UnmanagedType.CustomMarshaler,
|
|
MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))]
|
|
out System.Type typeInfo);
|
|
}
|
|
|
|
class Permission {
|
|
public string FullName {get;set;}
|
|
public string Name {get;set;}
|
|
public string Type {get;set;}
|
|
public bool Hidden {get;set;}
|
|
|
|
public bool IsGroup {get { return Type != "System.Boolean"; } }
|
|
|
|
public List<Permission> Children {get;set;}
|
|
|
|
public string FriendlyName {get;set;}
|
|
public string Description {get;set;}
|
|
|
|
public Permission(string FullName, string Name, string Type, CodeElements Attributes)
|
|
{
|
|
this.FullName = FullName;
|
|
this.Name = Name;
|
|
this.Type = Type;
|
|
|
|
Children = new List<Permission>();
|
|
|
|
if (Attributes.Count > 0){
|
|
CodeAttribute att = (CodeAttribute)Attributes.Item("ClaimDetails");
|
|
|
|
if (att.Children != null){
|
|
|
|
var attChildren = att.Children.OfType<CodeAttributeArgument>().ToArray();
|
|
this.FriendlyName = attChildren[0].Value.Trim('"');
|
|
this.Description = attChildren[1].Value.Trim('"');
|
|
|
|
if (attChildren.Length > 2) {
|
|
this.Hidden = bool.Parse(attChildren[2].Value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#> |