diff --git a/ExternalConnectors/ExternalConnectors.csproj b/ExternalConnectors/ExternalConnectors.csproj index b121be69..c6c49b4a 100644 --- a/ExternalConnectors/ExternalConnectors.csproj +++ b/ExternalConnectors/ExternalConnectors.csproj @@ -26,5 +26,8 @@ + + Form + diff --git a/ExternalConnectors/VO/VaultOpenbao.cs b/ExternalConnectors/VO/VaultOpenbao.cs index c41d9942..b39a1bc4 100644 --- a/ExternalConnectors/VO/VaultOpenbao.cs +++ b/ExternalConnectors/VO/VaultOpenbao.cs @@ -1,6 +1,8 @@ -using Newtonsoft.Json.Linq; +using Microsoft.Win32; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -15,10 +17,29 @@ namespace ExternalConnectors.VO { } public static class VaultOpenbao { - private static VaultClient GetClient(string url, string token) { + private static RegistryKey baseKey = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\mRemoteVaultOpenbao"); + private static string token = ""; + private static VaultClient GetClient() { + string url = (string)baseKey.GetValue("URL", ""); + if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(token)) { + using VaultOpenbaoConnectionForm voForm = new(); + voForm.tbUrl.Text = url; + _ = voForm.ShowDialog(); + if (voForm.DialogResult != DialogResult.OK) + throw new VaultOpenbaoException($"No credential provided", null); + url = voForm.tbUrl.Text; + token = voForm.tbToken.Text; + } IAuthMethodInfo authMethod = new TokenAuthMethodInfo(token); var vaultClientSettings = new VaultClientSettings(url, authMethod); - return new(vaultClientSettings); + VaultClient client = new(vaultClientSettings); + var sysInfo = client.V1.System.GetInitStatusAsync().Result; + if (!sysInfo) { + MessageBox.Show("Test connection failed", "Vault Openbao", MessageBoxButtons.OK, MessageBoxIcon.Error); + throw new VaultOpenbaoException($"Url not working", null); + } + baseKey.SetValue("URL", url); + return client; } private static void TestMountType(VaultClient vaultClient, string mount, int VaultOpenbaoSecretEngine) { switch (vaultClient.V1.System.GetSecretBackendAsync(mount).Result.Data.Type.Type) { @@ -28,8 +49,8 @@ namespace ExternalConnectors.VO { throw new VaultOpenbaoException($"Backend of type ldap does not match expected type {VaultOpenbaoSecretEngine}", null); } } - public static void ReadPasswordSSH(string url, string token, int secretEngine, string mount, string role, string username, out string password) { - VaultClient vaultClient = GetClient(url, token); + public static void ReadPasswordSSH(int secretEngine, string mount, string role, string username, out string password) { + VaultClient vaultClient = GetClient(); TestMountType(vaultClient, mount, secretEngine); switch (secretEngine) { case 0: @@ -45,8 +66,8 @@ namespace ExternalConnectors.VO { } } - public static void ReadPasswordRDP(string url, string token, int secretEngine, string mount, string role, ref string username, out string password) { - VaultClient vaultClient = GetClient(url, token); + public static void ReadPasswordRDP(int secretEngine, string mount, string role, ref string username, out string password) { + VaultClient vaultClient = GetClient(); TestMountType(vaultClient, mount, secretEngine); switch (secretEngine) { case 0: @@ -63,7 +84,7 @@ namespace ExternalConnectors.VO { username = ldaps.Data.Username; password = ldaps.Data.Password; return; - + default: throw new VaultOpenbaoException($"Backend of type {secretEngine} is not supported", null); } diff --git a/ExternalConnectors/VO/VaultOpenbaoConnectionForm.Designer.cs b/ExternalConnectors/VO/VaultOpenbaoConnectionForm.Designer.cs new file mode 100644 index 00000000..957d291f --- /dev/null +++ b/ExternalConnectors/VO/VaultOpenbaoConnectionForm.Designer.cs @@ -0,0 +1,184 @@ +namespace ExternalConnectors.VO +{ + partial class VaultOpenbaoConnectionForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() { + tbUrl = new TextBox(); + tbToken = new TextBox(); + btnOK = new Button(); + btnCancel = new Button(); + tableLayoutPanel1 = new TableLayoutPanel(); + label1 = new Label(); + label2 = new Label(); + tableLayoutPanel2 = new TableLayoutPanel(); + tableLayoutPanel1.SuspendLayout(); + tableLayoutPanel2.SuspendLayout(); + SuspendLayout(); + // + // tbUrl + // + tbUrl.Dock = DockStyle.Fill; + tbUrl.Location = new Point(174, 5); + tbUrl.Margin = new Padding(5); + tbUrl.Name = "tbUrl"; + tbUrl.Size = new Size(559, 27); + tbUrl.TabIndex = 0; + // + // tbToken + // + tbToken.Dock = DockStyle.Fill; + tbToken.Location = new Point(174, 57); + tbToken.Margin = new Padding(5); + tbToken.Name = "tbToken"; + tbToken.Size = new Size(559, 27); + tbToken.TabIndex = 2; + tbToken.UseSystemPasswordChar = true; + // + // btnOK + // + btnOK.Anchor = AnchorStyles.Right; + btnOK.DialogResult = DialogResult.OK; + btnOK.Location = new Point(250, 16); + btnOK.Margin = new Padding(5); + btnOK.Name = "btnOK"; + btnOK.Size = new Size(101, 35); + btnOK.TabIndex = 10; + btnOK.Text = "OK"; + btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + btnCancel.Anchor = AnchorStyles.Left; + btnCancel.DialogResult = DialogResult.Cancel; + btnCancel.Location = new Point(387, 16); + btnCancel.Margin = new Padding(5); + btnCancel.Name = "btnCancel"; + btnCancel.Size = new Size(101, 35); + btnCancel.TabIndex = 11; + btnCancel.Text = "Cancel"; + btnCancel.UseVisualStyleBackColor = true; + // + // tableLayoutPanel1 + // + tableLayoutPanel1.ColumnCount = 2; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 22.92994F)); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 77.07006F)); + tableLayoutPanel1.Controls.Add(label1, 0, 0); + tableLayoutPanel1.Controls.Add(label2, 0, 1); + tableLayoutPanel1.Controls.Add(tbUrl, 1, 0); + tableLayoutPanel1.Controls.Add(tbToken, 1, 1); + tableLayoutPanel1.Dock = DockStyle.Top; + tableLayoutPanel1.Location = new Point(0, 0); + tableLayoutPanel1.Margin = new Padding(5); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 3; + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 31F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 31F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 31F)); + tableLayoutPanel1.Size = new Size(738, 136); + tableLayoutPanel1.TabIndex = 12; + // + // label1 + // + label1.AutoSize = true; + label1.Dock = DockStyle.Fill; + label1.Location = new Point(5, 0); + label1.Margin = new Padding(5, 0, 5, 0); + label1.Name = "label1"; + label1.Size = new Size(159, 52); + label1.TabIndex = 2; + label1.Text = "Server URL"; + label1.TextAlign = ContentAlignment.MiddleLeft; + // + // label2 + // + label2.AutoSize = true; + label2.Dock = DockStyle.Fill; + label2.Location = new Point(5, 52); + label2.Margin = new Padding(5, 0, 5, 0); + label2.Name = "label2"; + label2.Size = new Size(159, 52); + label2.TabIndex = 4; + label2.Text = "Access Token"; + label2.TextAlign = ContentAlignment.MiddleLeft; + // + // tableLayoutPanel2 + // + tableLayoutPanel2.ColumnCount = 5; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 106F)); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 26F)); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 106F)); + tableLayoutPanel2.Controls.Add(btnOK, 1, 0); + tableLayoutPanel2.Controls.Add(btnCancel, 3, 0); + tableLayoutPanel2.Dock = DockStyle.Bottom; + tableLayoutPanel2.Location = new Point(0, 149); + tableLayoutPanel2.Margin = new Padding(5); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 1; + tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + tableLayoutPanel2.Size = new Size(738, 67); + tableLayoutPanel2.TabIndex = 13; + // + // VaultOpenbaoConnectionForm + // + AcceptButton = btnOK; + AutoScaleDimensions = new SizeF(8F, 20F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(738, 216); + Controls.Add(tableLayoutPanel2); + Controls.Add(tableLayoutPanel1); + FormBorderStyle = FormBorderStyle.FixedDialog; + Margin = new Padding(5); + MaximizeBox = false; + MinimizeBox = false; + Name = "VaultOpenbaoConnectionForm"; + SizeGripStyle = SizeGripStyle.Hide; + Text = "Vault/Openbao API Login Data"; + Activated += VaultOpenbaoConnectionForm_Activated; + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + tableLayoutPanel2.ResumeLayout(false); + ResumeLayout(false); + + } + + #endregion + + public System.Windows.Forms.TextBox tbUrl; + public System.Windows.Forms.TextBox tbToken; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + } +} \ No newline at end of file diff --git a/ExternalConnectors/VO/VaultOpenbaoConnectionForm.cs b/ExternalConnectors/VO/VaultOpenbaoConnectionForm.cs new file mode 100644 index 00000000..233ba1e5 --- /dev/null +++ b/ExternalConnectors/VO/VaultOpenbaoConnectionForm.cs @@ -0,0 +1,13 @@ +namespace ExternalConnectors.VO +{ + public partial class VaultOpenbaoConnectionForm : Form { + public VaultOpenbaoConnectionForm() { + InitializeComponent(); + + } + + private void VaultOpenbaoConnectionForm_Activated(object sender, EventArgs e) { + tbUrl.Focus(); + } + } +} diff --git a/ExternalConnectors/VO/VaultOpenbaoConnectionForm.resx b/ExternalConnectors/VO/VaultOpenbaoConnectionForm.resx new file mode 100644 index 00000000..8b2ff64a --- /dev/null +++ b/ExternalConnectors/VO/VaultOpenbaoConnectionForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/mRemoteNG/Connection/Protocol/PuttyBase.cs b/mRemoteNG/Connection/Protocol/PuttyBase.cs index b4a2dba6..5bdc7163 100644 --- a/mRemoteNG/Connection/Protocol/PuttyBase.cs +++ b/mRemoteNG/Connection/Protocol/PuttyBase.cs @@ -163,12 +163,7 @@ namespace mRemoteNG.Connection.Protocol } else if (InterfaceControl.Info.ExternalCredentialProvider == ExternalCredentialProvider.VaultOpenbao) { try { - RootNodeInfo? rootNode = InterfaceControl.Info?.GetRootParent() as RootNodeInfo; - if (rootNode == null) { - Event_ErrorOccured(this, "Secret Server Interface Error: No valid Openbao/Vault data found in root node.", 0); - return false; - } - ExternalConnectors.VO.VaultOpenbao.ReadPasswordSSH(rootNode.VaultOpenbaoUrl, rootNode.VaultOpenbaoToken, (int)InterfaceControl.Info?.VaultOpenbaoSecretEngine, InterfaceControl.Info?.VaultOpenbaoMount ?? "", InterfaceControl.Info?.VaultOpenbaoRole ?? "", InterfaceControl.Info?.Username ?? "root", out password); + ExternalConnectors.VO.VaultOpenbao.ReadPasswordSSH((int)InterfaceControl.Info?.VaultOpenbaoSecretEngine, InterfaceControl.Info?.VaultOpenbaoMount ?? "", InterfaceControl.Info?.VaultOpenbaoRole ?? "", InterfaceControl.Info?.Username ?? "root", out password); } catch (ExternalConnectors.VO.VaultOpenbaoException ex) { Event_ErrorOccured(this, "Secret Server Interface Error: " + ex.Message, 0); } diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol.cs index a3dc8a96..9a8fcb8c 100644 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol.cs +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol.cs @@ -483,14 +483,9 @@ namespace mRemoteNG.Connection.Protocol.RDP else if (InterfaceControl.Info.ExternalCredentialProvider == ExternalCredentialProvider.VaultOpenbao) { try { - RootNodeInfo? rootNode = connectionInfo?.GetRootParent() as RootNodeInfo; - if (rootNode == null) { - Event_ErrorOccured(this, "Secret Server Interface Error: No valid Openbao/Vault data found in root node.", 0); - return; - } if (connectionInfo.VaultOpenbaoSecretEngine == VaultOpenbaoSecretEngine.Kv) gwu = connectionInfo.RDGatewayUsername; - ExternalConnectors.VO.VaultOpenbao.ReadPasswordRDP(rootNode.VaultOpenbaoUrl, rootNode.VaultOpenbaoToken, (int)connectionInfo.VaultOpenbaoSecretEngine, connectionInfo.VaultOpenbaoMount, connectionInfo.VaultOpenbaoRole, ref gwu, out gwp); + ExternalConnectors.VO.VaultOpenbao.ReadPasswordRDP((int)connectionInfo.VaultOpenbaoSecretEngine, connectionInfo.VaultOpenbaoMount, connectionInfo.VaultOpenbaoRole, ref gwu, out gwp); } catch (ExternalConnectors.VO.VaultOpenbaoException ex) { Event_ErrorOccured(this, "Secret Server Interface Error: " + ex.Message, 0); } @@ -609,14 +604,9 @@ namespace mRemoteNG.Connection.Protocol.RDP } else if (InterfaceControl.Info.ExternalCredentialProvider == ExternalCredentialProvider.VaultOpenbao) { try { - RootNodeInfo? rootNode = connectionInfo?.GetRootParent() as RootNodeInfo; - if (rootNode == null) { - Event_ErrorOccured(this, "Secret Server Interface Error: No valid Openbao/Vault data found in root node.", 0); - return; - } if(connectionInfo.VaultOpenbaoSecretEngine == VaultOpenbaoSecretEngine.Kv) userName = connectionInfo?.Username ?? ""; - ExternalConnectors.VO.VaultOpenbao.ReadPasswordRDP(rootNode.VaultOpenbaoUrl, rootNode.VaultOpenbaoToken, (int)connectionInfo.VaultOpenbaoSecretEngine, connectionInfo?.VaultOpenbaoMount ?? "", connectionInfo?.VaultOpenbaoRole ?? "", ref userName, out password); + ExternalConnectors.VO.VaultOpenbao.ReadPasswordRDP((int)connectionInfo.VaultOpenbaoSecretEngine, connectionInfo?.VaultOpenbaoMount ?? "", connectionInfo?.VaultOpenbaoRole ?? "", ref userName, out password); } catch (ExternalConnectors.VO.VaultOpenbaoException ex) { Event_ErrorOccured(this, "Secret Server Interface Error: " + ex.Message, 0); }