diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ad80dc7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +# Autosave files +*~ + +# build +[Oo]bj/ +[Bb]in/ +builds/ +packages/ +TestResults/ +PublishProfiles/ + +# globs +Makefile.in +*.DS_Store +*.sln.cache +*.suo +*.cache +*.pidb +*.userprefs +*.usertasks +config.log +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.user +*.tar.gz +tarballs/ +test-results/ +Thumbs.db + +# Mac bundle stuff +*.dmg +*.app + +# resharper +*_Resharper.* +*.Resharper + +# dotCover +*.dotCover +.idea +.vs +project.lock.json +*nuget.targets +*.nuget.props +UpgradeLog.htm diff --git a/RoleManagement/Program.cs b/RoleManagement/Program.cs new file mode 100644 index 0000000..df7e884 --- /dev/null +++ b/RoleManagement/Program.cs @@ -0,0 +1,307 @@ +// _ __ +// | |/ /___ ___ _ __ ___ _ _ ® +// | ' "); + var answer = await GetInputManager().ReadLine(); + if (int.TryParse(answer, out var choice)) + { + switch (choice) + { + case 1: + { + var table = new Tabulate(4); + table.AddHeader("Node ID", "Node Name", "Parent Id", "Isolated Node"); + foreach (var node in enterpriseData.Nodes) + { + table.AddRow(node.Id, node.DisplayName, node.ParentNodeId > 0 ? node.ParentNodeId.ToString() : "", node.RestrictVisibility ? "Isolated" : ""); + } + table.Dump(); + } + + break; + case 2: + { + var table = new Tabulate(5); + table.AddHeader("User ID", "User Email", "User Name", "Node ID", "Status"); + foreach (var user in enterpriseData.Users) + { + table.AddRow(user.Id, user.Email, user.DisplayName, user.ParentNodeId, user.UserStatus); + } + table.Dump(); + } + + break; + + case 3: + { + var table = new Tabulate(5); + table.AddHeader("Role ID", "Role Name", "Node ID", "Cascade?", "Users in Role"); + foreach (var role in roleData.Roles) + { + var cnt = roleData.GetUsersForRole(role.Id).Count(); + table.AddRow(role.Id, role.DisplayName, role.ParentNodeId, role.VisibleBelow, cnt); + } + table.Dump(); + } + + break; + + case 4: + { + Console.Write("\nNode Name: "); + var nodeName = await GetInputManager().ReadLine(); + if (!string.IsNullOrEmpty(nodeName)) + { + Console.Write("Parent Node ID (empty for Root Node): "); + EnterpriseNode parentNode = null; + var parent = await GetInputManager().ReadLine(); + if (!string.IsNullOrEmpty(parent)) + { + if (long.TryParse(parent, out var n)) + { + var node = enterpriseData.Nodes.FirstOrDefault(x => x.Id == n); + if (node == null) + { + Console.WriteLine($"Parent node ID \"{parent}\" not found."); + } + } + } + else + { + parentNode = enterpriseData.RootNode; + } + + if (parentNode != null) + { + try + { + var n = await enterpriseData.CreateNode(nodeName, parentNode); + Console.WriteLine($"Node created. Node ID = {n.Id}"); + await enterpriseLoader.Load(); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } + } + } + } + break; + + case 5: + { + Console.Write("Enter Node ID to toggle Node Isolation: "); + EnterpriseNode node = null; + answer = await GetInputManager().ReadLine(); + if (!string.IsNullOrEmpty(answer)) + { + if (long.TryParse(answer, out var n)) + { + var nd = enterpriseData.Nodes.FirstOrDefault(x => x.Id == n); + if (nd == null) + { + Console.WriteLine($"Parent node ID \"{answer}\" not found."); + } + else if (ReferenceEquals(nd, enterpriseData.RootNode)) + { + Console.WriteLine($"Cannot change Node Isolation on the Root node."); + } + else + { + node = nd; + } + } + } + if (node != null) + { + try + { + await enterpriseData.SetRestrictVisibility(node.Id); + Console.WriteLine($"Node isolation id toggled on Node ID: {node.Id}"); + await enterpriseLoader.Load(); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } + + } + + } + break; + + case 6: + { + EnterpriseRole role = null; + Console.Write("Enter Role ID or Role Node: "); + answer = await GetInputManager().ReadLine(); + if (!string.IsNullOrEmpty(answer)) + { + if (long.TryParse(answer, out var n)) + { + roleData.TryGetRole(n, out role); + } + if (role == null) + { + role = roleData.Roles.FirstOrDefault(x => string.Equals(x.DisplayName, answer, StringComparison.CurrentCultureIgnoreCase)); + } + if (role == null) + { + Console.WriteLine($"Role \"{answer}\" not found."); + return; + } + } + else + { + return; + } + Console.WriteLine($"Current role:\nRole ID: {role.Id}\nRole Name: {role.DisplayName}"); + + EnterpriseUser user = null; + Console.Write("Enter User ID or User Email: "); + answer = await GetInputManager().ReadLine(); + if (!string.IsNullOrEmpty(answer)) + { + if (long.TryParse(answer, out var n)) + { + enterpriseData.TryGetUserById(n, out user); + } + if (user == null) + { + enterpriseData.TryGetUserByEmail(answer, out user); + } + if (user == null) + { + Console.WriteLine($"User \"{answer}\" not found."); + return; + } + } + else + { + return; + } + Console.WriteLine($"\nUser ID: {user.Id}\nEmail: {user.Email}"); + + await roleData.AddUserToRole(role.Id, user.Id); + + Console.WriteLine($"User \"{user.Email}\" added to role \"{role.DisplayName}\""); + } + break; + } + } + else + { + if (string.Equals(answer, "q", StringComparison.InvariantCultureIgnoreCase)) + { + break; + } + Console.WriteLine($"Invalid choice: {answer}"); + } + } + } + + private static void Main() + { + Console.CancelKeyPress += (s, e) => { Environment.Exit(-1); }; + + _ = Task.Run(async () => + { + try + { + await MainLoop(); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } + + Environment.Exit(0); + }); + + InputManager.Run(); + } + + } + +} \ No newline at end of file diff --git a/RoleManagement/RoleDataManagement.cs b/RoleManagement/RoleDataManagement.cs new file mode 100644 index 0000000..58fdc34 --- /dev/null +++ b/RoleManagement/RoleDataManagement.cs @@ -0,0 +1,200 @@ +using KeeperSecurity.Commands; +using KeeperSecurity.Authentication; +using System.Threading.Tasks; +using KeeperSecurity.Utils; +using System.Collections.Generic; +using Enterprise; +using System; +using System.Diagnostics; +using Google.Protobuf; +using KeeperSecurity.Enterprise; + +namespace Sample +{ + public interface IRoleDataManagement : IRoleData + { + Task CreateRole(string roleName, long nodeId, bool visibleBelow, bool newUserInherit); + Task DeleteRole(long roleId); + + Task AddUserToRole(long roleId, long userId); + Task AddUserToAdminRole(long roleId, long userId, byte[] userRsaPublicKey); + Task RemoveUserFromRole(long roleId, long userId); + Task AddTeamToRole(long roleId, string teamUid); + Task RemoveTeamFromRole(long roleId, string teamUid); + } + + public class RoleDataManagement : RoleData, IRoleDataManagement + { + private Dictionary _adminRoleKeys = new Dictionary(); + + private async Task GetRoleKey(long roleId) + { + lock (_adminRoleKeys) + { + if (_adminRoleKeys.TryGetValue(roleId, out var result)) + { + return result; + } + } + + var krq = new GetEnterpriseDataKeysRequest(); + krq.RoleId.Add(roleId); + var krs = await Enterprise.Auth.ExecuteAuthRest("enterprise/get_enterprise_data_keys", krq); + foreach (var rKey in krs.ReEncryptedRoleKey) + { + if (rKey.RoleId == roleId) + { + try + { + var roleKey = CryptoUtils.DecryptAesV2(rKey.EncryptedRoleKey.ToByteArray(), Enterprise.TreeKey); + lock (_adminRoleKeys) + { + if (!_adminRoleKeys.ContainsKey(roleId)) + { + _adminRoleKeys.Add(roleId, roleKey); + } + return roleKey; + } + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + } + } + + foreach (var rKey in krs.RoleKey) + { + if (rKey.RoleId == roleId) + { + byte[] roleKey = null; + try + { + switch (rKey.KeyType) + { + case EncryptedKeyType.KtEncryptedByDataKey: + roleKey = CryptoUtils.DecryptAesV1(rKey.EncryptedKey.Base64UrlDecode(), Enterprise.Auth.AuthContext.DataKey); + break; + case EncryptedKeyType.KtEncryptedByPublicKey: + roleKey = CryptoUtils.DecryptRsa(rKey.EncryptedKey.Base64UrlDecode(), Enterprise.Auth.AuthContext.PrivateKey); + break; + } + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + + if (roleKey != null) + { + lock (_adminRoleKeys) + { + if (!_adminRoleKeys.ContainsKey(roleId)) + { + _adminRoleKeys.Add(roleId, roleKey); + } + return roleKey; + } + } + } + } + + return null; + } + + public async Task CreateRole(string roleName, long nodeId, bool visibleBelow, bool newUserInherit) + { + var encryptedData = new EncryptedData + { + DisplayName = roleName + }; + + var roleId = await Enterprise.GetEnterpriseId(); + var rq = new RoleAddCommand + { + RoleId = roleId, + NodeId = nodeId, + EncryptedData = EnterpriseUtils.EncryptEncryptedData(encryptedData, Enterprise.TreeKey), + VisibleBelow = visibleBelow, + NewUserInherit = newUserInherit + }; + + await Enterprise.Auth.ExecuteAuthCommand(rq); + await Enterprise.Load(); + return TryGetRole(roleId, out var role) ? role : null; + } + + public async Task DeleteRole(long roleId) + { + await Enterprise.Auth.ExecuteAuthCommand(new RoleDeleteCommand { RoleId = roleId }); ; + await Enterprise.Load(); + } + + public async Task AddUserToRole(long roleId, long userId) + { + var rq = new RoleUserAddCommand + { + RoleId = roleId, + EnterpriseUserId = userId, + }; + + await Enterprise.Auth.ExecuteAuthCommand(rq); + await Enterprise.Load(); + } + + public async Task AddUserToAdminRole(long roleId, long userId, byte[] userRsaPublicKey) + { + var publicKey = CryptoUtils.LoadPublicKey(userRsaPublicKey); + var rq = new RoleUserAddCommand + { + RoleId = roleId, + EnterpriseUserId = userId, + TreeKey = CryptoUtils.EncryptRsa(Enterprise.TreeKey, publicKey).Base64UrlEncode(), + }; + var roleKey = await GetRoleKey(roleId); + if (roleKey != null) + { + rq.RoleAdminKey = CryptoUtils.EncryptRsa(roleKey, publicKey).Base64UrlEncode(); + } + await Enterprise.Auth.ExecuteAuthCommand(rq); + await Enterprise.Load(); + } + + public async Task RemoveUserFromRole(long roleId, long userId) + { + var rq = new RoleUserRemoveCommand + { + RoleId = roleId, + EnterpriseUserId = userId, + }; + + await Enterprise.Auth.ExecuteAuthCommand(rq); + await Enterprise.Load(); + } + + public async Task AddTeamToRole(long roleId, string teamUid) { + var rq = new RoleTeams(); + rq.RoleTeam.Add(new RoleTeam + { + RoleId = roleId, + TeamUid = ByteString.CopyFrom(teamUid.Base64UrlDecode()), + }); + + await Enterprise.Auth.ExecuteAuthRest("enterprise/role_team_add", rq); + await Enterprise.Load(); + } + + public async Task RemoveTeamFromRole(long roleId, string teamUid) + { + var rq = new RoleTeams(); + rq.RoleTeam.Add(new RoleTeam + { + RoleId = roleId, + TeamUid = ByteString.CopyFrom(teamUid.Base64UrlDecode()), + }); + + await Enterprise.Auth.ExecuteAuthRest("enterprise/role_team_remove", rq); + await Enterprise.Load(); + } + } +} diff --git a/RoleManagement/RoleManagement.csproj b/RoleManagement/RoleManagement.csproj new file mode 100644 index 0000000..f1861f3 --- /dev/null +++ b/RoleManagement/RoleManagement.csproj @@ -0,0 +1,13 @@ + + + + Exe + net5.0 + + + + + + + + diff --git a/RoleManagement/RoleManagement.sln b/RoleManagement/RoleManagement.sln new file mode 100644 index 0000000..765b5e3 --- /dev/null +++ b/RoleManagement/RoleManagement.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31424.327 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoleManagement", "RoleManagement.csproj", "{06BB0556-017E-4117-A1C9-327104CDE580}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {06BB0556-017E-4117-A1C9-327104CDE580}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {06BB0556-017E-4117-A1C9-327104CDE580}.Debug|Any CPU.Build.0 = Debug|Any CPU + {06BB0556-017E-4117-A1C9-327104CDE580}.Release|Any CPU.ActiveCfg = Release|Any CPU + {06BB0556-017E-4117-A1C9-327104CDE580}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6B7892C7-EED7-4A62-BC08-142772216056} + EndGlobalSection +EndGlobal