<#@ 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 permissions = new List(); List groups = new List(); 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); #> // // 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, Action, string, string, bool>> _roleClaims; private static ClaimNavigatorItem _claimNavigator; static Claims() { #region Role Claim Dictionary _roleClaims = new Dictionary, Action, string, string, bool>>() { <#WriteAccessHashes(permissionRoot);#> }; #endregion #region Role Claim Navigator _claimNavigator = <#WriteNavigator(permissionRoot);#>; #endregion } public static ClaimNavigatorItem RoleClaimNavigator { get { return _claimNavigator; } } internal static Tuple, Action, 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 GetClaimAccessor(string ClaimKey) { if (_roleClaims.TryGetValue(ClaimKey, out var claimDef)) return claimDef.Item1; throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey)); } public static Action GetClaimSetter(string ClaimKey) { if (_roleClaims.TryGetValue(ClaimKey, out var claimDef)) return claimDef.Item2; throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey)); } public static Tuple 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 ClaimKeys) { var c = new RoleClaims(); foreach (var claimKey in ClaimKeys) c.Set(claimKey, true); return c; } public static List 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 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() {"); 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() {{", 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 parents = new Stack(); parents.Push("c"); foreach (var pChild in root.Children) WriteAdministratorClaims_Recurse(pChild, parents); PopIndent(); } void WriteAdministratorClaims_Recurse(Permission p, Stack 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 parents = new Stack(); 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 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, Action, 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("/// {0}", p.FriendlyName); WriteLine("/// {0}", p.Description); WriteLine("/// "); 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("/// {0}", p.FriendlyName); WriteLine("/// {0}", p.Description); WriteLine("/// "); WriteLine("public const string {0} = \"{1}{0}\";", p.Name, Prefix); } } Permission BuildHierarchy(List groups, List 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 groups, List permissions){ foreach (var ns in item.FileCodeModel.CodeElements.OfType()) { foreach (var cl in ns.Members.OfType()) { var g = BuildPermission(cl); groups.Add(g); foreach (var pr in cl.Members.OfType()) { 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 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 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(); if (Attributes.Count > 0){ CodeAttribute att = (CodeAttribute)Attributes.Item("ClaimDetails"); if (att.Children != null){ var attChildren = att.Children.OfType().ToArray(); this.FriendlyName = attChildren[0].Value.Trim('"'); this.Description = attChildren[1].Value.Trim('"'); if (attChildren.Length > 2) { this.Hidden = bool.Parse(attChildren[2].Value); } } } } } #>