From afbb84bca4f1b2d50dac462da59b1a2c6ba50923 Mon Sep 17 00:00:00 2001 From: Corey Kosak Date: Sat, 31 Aug 2024 14:59:02 -0400 Subject: [PATCH] feat(csharp/ExcelAddIn): allow insecure JSON URL for Core+; choose python/groovy for Core (#6008) Add GUI elements (and wire them up) 1. ... for allowing insecure JSON URL fetches for Enterprise Core+ 2. ...for selecting the session type (groovy vs python) for Community Core 3. ...for closing the "Set Credentials" dialog box upon setting the credentials --- .../factories/CredentialsDialogFactory.cs | 2 + .../factories/SessionBaseFactory.cs | 13 ++- csharp/ExcelAddIn/models/Credentials.cs | 17 ++-- .../viewmodels/CredentialsDialogViewModel.cs | 50 +++++++++- .../views/CredentialsDialog.Designer.cs | 97 +++++++++++++++---- csharp/ExcelAddIn/views/CredentialsDialog.cs | 7 ++ .../ExcelAddIn/views/CredentialsDialog.resx | 4 +- .../dhe_client/session/SessionManager.cs | 11 +++ 8 files changed, 168 insertions(+), 33 deletions(-) diff --git a/csharp/ExcelAddIn/factories/CredentialsDialogFactory.cs b/csharp/ExcelAddIn/factories/CredentialsDialogFactory.cs index 4212c250c31..adada638e9c 100644 --- a/csharp/ExcelAddIn/factories/CredentialsDialogFactory.cs +++ b/csharp/ExcelAddIn/factories/CredentialsDialogFactory.cs @@ -19,6 +19,8 @@ void OnSetCredentialsButtonClicked() { if (cvm.IsDefault) { sm.SetDefaultCredentials(newCreds); } + + credentialsDialog!.Close(); } void OnTestCredentialsButtonClicked() { diff --git a/csharp/ExcelAddIn/factories/SessionBaseFactory.cs b/csharp/ExcelAddIn/factories/SessionBaseFactory.cs index 0719e58fc2f..44886d6a16d 100644 --- a/csharp/ExcelAddIn/factories/SessionBaseFactory.cs +++ b/csharp/ExcelAddIn/factories/SessionBaseFactory.cs @@ -9,12 +9,21 @@ internal static class SessionBaseFactory { public static SessionBase Create(CredentialsBase credentials, WorkerThread workerThread) { return credentials.AcceptVisitor( core => { - var client = Client.Connect(core.ConnectionString, new ClientOptions()); + var options = new ClientOptions(); + options.SetSessionType(core.SessionTypeIsPython ? "python" : "groovy"); + var client = Client.Connect(core.ConnectionString, options); return new CoreSession(client); }, corePlus => { - var session = SessionManager.FromUrl("Deephaven Excel", corePlus.JsonUrl); + var handler = new HttpClientHandler(); + if (!corePlus.ValidateCertificate) { + handler.ClientCertificateOptions = ClientCertificateOption.Manual; + handler.ServerCertificateCustomValidationCallback = (_, _, _, _) => true; + } + var hc = new HttpClient(handler); + var json = hc.GetStringAsync(corePlus.JsonUrl).Result; + var session = SessionManager.FromJson("Deephaven Excel", json); if (!session.PasswordAuthentication(corePlus.User, corePlus.Password, corePlus.OperateAs)) { throw new Exception("Authentication failed"); } diff --git a/csharp/ExcelAddIn/models/Credentials.cs b/csharp/ExcelAddIn/models/Credentials.cs index 3368a59de04..0a2ffdc6b60 100644 --- a/csharp/ExcelAddIn/models/Credentials.cs +++ b/csharp/ExcelAddIn/models/Credentials.cs @@ -3,21 +3,25 @@ public abstract class CredentialsBase(EndpointId id) { public readonly EndpointId Id = id; - public static CredentialsBase OfCore(EndpointId id, string connectionString) { - return new CoreCredentials(id, connectionString); + public static CredentialsBase OfCore(EndpointId id, string connectionString, bool sessionTypeIsPython) { + return new CoreCredentials(id, connectionString, sessionTypeIsPython); } public static CredentialsBase OfCorePlus(EndpointId id, string jsonUrl, string userId, - string password, string operateAs) { - return new CorePlusCredentials(id, jsonUrl, userId, password, operateAs); + string password, string operateAs, bool validateCertificate) { + return new CorePlusCredentials(id, jsonUrl, userId, password, operateAs, validateCertificate); } public abstract T AcceptVisitor(Func ofCore, Func ofCorePlus); } -public sealed class CoreCredentials(EndpointId id, string connectionString) : CredentialsBase(id) { +public sealed class CoreCredentials( + EndpointId id, + string connectionString, + bool sessionTypeIsPython) : CredentialsBase(id) { public readonly string ConnectionString = connectionString; + public readonly bool SessionTypeIsPython = sessionTypeIsPython; public override T AcceptVisitor(Func ofCore, Func ofCorePlus) { return ofCore(this); @@ -25,11 +29,12 @@ public override T AcceptVisitor(Func ofCore, Func(Func ofCore, Func ofCorePlus) { return ofCorePlus(this); diff --git a/csharp/ExcelAddIn/viewmodels/CredentialsDialogViewModel.cs b/csharp/ExcelAddIn/viewmodels/CredentialsDialogViewModel.cs index c25f6b2faa7..6634640031f 100644 --- a/csharp/ExcelAddIn/viewmodels/CredentialsDialogViewModel.cs +++ b/csharp/ExcelAddIn/viewmodels/CredentialsDialogViewModel.cs @@ -16,11 +16,14 @@ public static CredentialsDialogViewModel OfIdButOtherwiseEmpty(string id) { } public static CredentialsDialogViewModel OfIdAndCredentials(string id, CredentialsBase credentials) { - var result = new CredentialsDialogViewModel { Id = id }; + var result = new CredentialsDialogViewModel { + Id = credentials.Id.Id + }; _ = credentials.AcceptVisitor( core => { result._isCorePlus = false; result.ConnectionString = core.ConnectionString; + result.SessionTypeIsPython = core.SessionTypeIsPython; return Unit.Instance; }, corePlus => { @@ -29,6 +32,7 @@ public static CredentialsDialogViewModel OfIdAndCredentials(string id, Credentia result.UserId = corePlus.User; result.Password = corePlus.Password; result.OperateAs = corePlus.OperateAs; + result.ValidateCertificate = corePlus.ValidateCertificate; return Unit.Instance; }); @@ -38,12 +42,14 @@ public static CredentialsDialogViewModel OfIdAndCredentials(string id, Credentia private string _id = ""; private bool _isDefault = false; private bool _isCorePlus = true; + private bool _sessionTypeIsPython = true; // Core properties private string _connectionString = ""; // Core+ properties private string _jsonUrl = ""; + private bool _validateCertificate = true; private string _userId = ""; private string _password = ""; private string _operateAs = ""; @@ -80,8 +86,8 @@ void CheckMissing(string field, string name) { var epId = new EndpointId(_id); result = _isCorePlus - ? CredentialsBase.OfCorePlus(epId, _jsonUrl, _userId, _password, _operateAs) - : CredentialsBase.OfCore(epId, _connectionString); + ? CredentialsBase.OfCorePlus(epId, _jsonUrl, _userId, _password, _operateAs, _validateCertificate) + : CredentialsBase.OfCore(epId, _connectionString, _sessionTypeIsPython); return true; } @@ -201,6 +207,44 @@ public string OperateAs { } } + public bool ValidateCertificate { + get => _validateCertificate; + set { + if (_validateCertificate == value) { + return; + } + + _validateCertificate = value; + OnPropertyChanged(); + } + } + + public bool SessionTypeIsPython { + get => _sessionTypeIsPython; + set { + if (_sessionTypeIsPython == value) { + return; + } + + _sessionTypeIsPython = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(SessionTypeIsGroovy)); + } + } + + public bool SessionTypeIsGroovy { + get => !_sessionTypeIsPython; + set { + if (!_sessionTypeIsPython == value) { + return; + } + + _sessionTypeIsPython = !value; + OnPropertyChanged(); + OnPropertyChanged(nameof(SessionTypeIsPython)); + } + } + private void OnPropertyChanged([CallerMemberName] string? name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } diff --git a/csharp/ExcelAddIn/views/CredentialsDialog.Designer.cs b/csharp/ExcelAddIn/views/CredentialsDialog.Designer.cs index a554e61e2b2..44d21cf57d1 100644 --- a/csharp/ExcelAddIn/views/CredentialsDialog.Designer.cs +++ b/csharp/ExcelAddIn/views/CredentialsDialog.Designer.cs @@ -25,6 +25,7 @@ protected override void Dispose(bool disposing) { private void InitializeComponent() { flowLayoutPanel1 = new FlowLayoutPanel(); corePlusPanel = new Panel(); + validateCertCheckBox = new CheckBox(); operateAsBox = new TextBox(); passwordBox = new TextBox(); label5 = new Label(); @@ -36,7 +37,11 @@ private void InitializeComponent() { corePanel = new Panel(); connectionStringBox = new TextBox(); label2 = new Label(); + groupBox1 = new GroupBox(); + sessionTypeIsGroovyButton = new RadioButton(); + sessionTypeIsPythonButton = new RadioButton(); finalPanel = new Panel(); + makeDefaultCheckBox = new CheckBox(); testResultsTextBox = new TextBox(); testResultsLabel = new Label(); testCredentialsButton = new Button(); @@ -46,10 +51,10 @@ private void InitializeComponent() { endpointIdBox = new TextBox(); label1 = new Label(); connectionTypeGroup = new GroupBox(); - makeDefaultCheckBox = new CheckBox(); flowLayoutPanel1.SuspendLayout(); corePlusPanel.SuspendLayout(); corePanel.SuspendLayout(); + groupBox1.SuspendLayout(); finalPanel.SuspendLayout(); connectionTypeGroup.SuspendLayout(); SuspendLayout(); @@ -61,11 +66,12 @@ private void InitializeComponent() { flowLayoutPanel1.Controls.Add(finalPanel); flowLayoutPanel1.Location = new Point(28, 160); flowLayoutPanel1.Name = "flowLayoutPanel1"; - flowLayoutPanel1.Size = new Size(994, 531); + flowLayoutPanel1.Size = new Size(994, 676); flowLayoutPanel1.TabIndex = 200; // // corePlusPanel // + corePlusPanel.Controls.Add(validateCertCheckBox); corePlusPanel.Controls.Add(operateAsBox); corePlusPanel.Controls.Add(passwordBox); corePlusPanel.Controls.Add(label5); @@ -76,9 +82,20 @@ private void InitializeComponent() { corePlusPanel.Controls.Add(label3); corePlusPanel.Location = new Point(3, 3); corePlusPanel.Name = "corePlusPanel"; - corePlusPanel.Size = new Size(991, 242); + corePlusPanel.Size = new Size(991, 299); corePlusPanel.TabIndex = 210; // + // validateCertCheckBox + // + validateCertCheckBox.AutoSize = true; + validateCertCheckBox.Location = new Point(192, 240); + validateCertCheckBox.Name = "validateCertCheckBox"; + validateCertCheckBox.RightToLeft = RightToLeft.No; + validateCertCheckBox.Size = new Size(183, 29); + validateCertCheckBox.TabIndex = 216; + validateCertCheckBox.Text = "Validate Certificate"; + validateCertCheckBox.UseVisualStyleBackColor = true; + // // operateAsBox // operateAsBox.Location = new Point(189, 183); @@ -148,9 +165,10 @@ private void InitializeComponent() { // corePanel.Controls.Add(connectionStringBox); corePanel.Controls.Add(label2); - corePanel.Location = new Point(3, 251); + corePanel.Controls.Add(groupBox1); + corePanel.Location = new Point(3, 308); corePanel.Name = "corePanel"; - corePanel.Size = new Size(991, 76); + corePanel.Size = new Size(991, 170); corePanel.TabIndex = 220; // // connectionStringBox @@ -169,6 +187,39 @@ private void InitializeComponent() { label2.TabIndex = 0; label2.Text = "Connection String"; // + // groupBox1 + // + groupBox1.Controls.Add(sessionTypeIsGroovyButton); + groupBox1.Controls.Add(sessionTypeIsPythonButton); + groupBox1.Location = new Point(18, 80); + groupBox1.Name = "groupBox1"; + groupBox1.Size = new Size(970, 71); + groupBox1.TabIndex = 231; + groupBox1.TabStop = false; + groupBox1.Text = "Session Type"; + // + // sessionTypeIsGroovyButton + // + sessionTypeIsGroovyButton.AutoSize = true; + sessionTypeIsGroovyButton.Location = new Point(338, 30); + sessionTypeIsGroovyButton.Name = "sessionTypeIsGroovyButton"; + sessionTypeIsGroovyButton.Size = new Size(95, 29); + sessionTypeIsGroovyButton.TabIndex = 1; + sessionTypeIsGroovyButton.TabStop = true; + sessionTypeIsGroovyButton.Text = "Groovy"; + sessionTypeIsGroovyButton.UseVisualStyleBackColor = true; + // + // sessionTypeIsPythonButton + // + sessionTypeIsPythonButton.AutoSize = true; + sessionTypeIsPythonButton.Location = new Point(192, 30); + sessionTypeIsPythonButton.Name = "sessionTypeIsPythonButton"; + sessionTypeIsPythonButton.Size = new Size(93, 29); + sessionTypeIsPythonButton.TabIndex = 0; + sessionTypeIsPythonButton.TabStop = true; + sessionTypeIsPythonButton.Text = "Python"; + sessionTypeIsPythonButton.UseVisualStyleBackColor = true; + // // finalPanel // finalPanel.Controls.Add(makeDefaultCheckBox); @@ -176,11 +227,21 @@ private void InitializeComponent() { finalPanel.Controls.Add(testResultsLabel); finalPanel.Controls.Add(testCredentialsButton); finalPanel.Controls.Add(setCredentialsButton); - finalPanel.Location = new Point(3, 333); + finalPanel.Location = new Point(3, 484); finalPanel.Name = "finalPanel"; - finalPanel.Size = new Size(991, 132); + finalPanel.Size = new Size(991, 152); finalPanel.TabIndex = 230; // + // makeDefaultCheckBox + // + makeDefaultCheckBox.AutoSize = true; + makeDefaultCheckBox.Location = new Point(599, 70); + makeDefaultCheckBox.Name = "makeDefaultCheckBox"; + makeDefaultCheckBox.Size = new Size(143, 29); + makeDefaultCheckBox.TabIndex = 234; + makeDefaultCheckBox.Text = "Make Default"; + makeDefaultCheckBox.UseVisualStyleBackColor = true; + // // testResultsTextBox // testResultsTextBox.Location = new Point(189, 17); @@ -220,7 +281,7 @@ private void InitializeComponent() { // isCorePlusRadioButton // isCorePlusRadioButton.AutoSize = true; - isCorePlusRadioButton.Location = new Point(6, 39); + isCorePlusRadioButton.Location = new Point(192, 30); isCorePlusRadioButton.Name = "isCorePlusRadioButton"; isCorePlusRadioButton.Size = new Size(169, 29); isCorePlusRadioButton.TabIndex = 110; @@ -231,7 +292,7 @@ private void InitializeComponent() { // isCoreRadioButton // isCoreRadioButton.AutoSize = true; - isCoreRadioButton.Location = new Point(195, 39); + isCoreRadioButton.Location = new Point(388, 30); isCoreRadioButton.Name = "isCoreRadioButton"; isCoreRadioButton.Size = new Size(172, 29); isCoreRadioButton.TabIndex = 111; @@ -266,21 +327,11 @@ private void InitializeComponent() { connectionTypeGroup.TabStop = false; connectionTypeGroup.Text = "Connection Type"; // - // makeDefaultCheckBox - // - makeDefaultCheckBox.AutoSize = true; - makeDefaultCheckBox.Location = new Point(599, 70); - makeDefaultCheckBox.Name = "makeDefaultCheckBox"; - makeDefaultCheckBox.Size = new Size(143, 29); - makeDefaultCheckBox.TabIndex = 234; - makeDefaultCheckBox.Text = "Make Default"; - makeDefaultCheckBox.UseVisualStyleBackColor = true; - // // CredentialsDialog // AutoScaleDimensions = new SizeF(10F, 25F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(1086, 714); + ClientSize = new Size(1086, 887); Controls.Add(connectionTypeGroup); Controls.Add(label1); Controls.Add(endpointIdBox); @@ -292,6 +343,8 @@ private void InitializeComponent() { corePlusPanel.PerformLayout(); corePanel.ResumeLayout(false); corePanel.PerformLayout(); + groupBox1.ResumeLayout(false); + groupBox1.PerformLayout(); finalPanel.ResumeLayout(false); finalPanel.PerformLayout(); connectionTypeGroup.ResumeLayout(false); @@ -326,5 +379,9 @@ private void InitializeComponent() { private Label testResultsLabel; private TextBox testResultsTextBox; private CheckBox makeDefaultCheckBox; + private CheckBox validateCertCheckBox; + private GroupBox groupBox1; + private RadioButton sessionTypeIsGroovyButton; + private RadioButton sessionTypeIsPythonButton; } } \ No newline at end of file diff --git a/csharp/ExcelAddIn/views/CredentialsDialog.cs b/csharp/ExcelAddIn/views/CredentialsDialog.cs index 1453b8703c4..4ca2260aec1 100644 --- a/csharp/ExcelAddIn/views/CredentialsDialog.cs +++ b/csharp/ExcelAddIn/views/CredentialsDialog.cs @@ -34,11 +34,18 @@ public CredentialsDialog(CredentialsDialogViewModel vm, Action onSetCredentialsB userIdBox.DataBindings.Add(nameof(userIdBox.Text), vm, nameof(vm.UserId)); passwordBox.DataBindings.Add(nameof(passwordBox.Text), vm, nameof(vm.Password)); operateAsBox.DataBindings.Add(nameof(operateAsBox.Text), vm, nameof(vm.OperateAs)); + validateCertCheckBox.DataBindings.Add(nameof(validateCertCheckBox.Checked), vm, nameof(vm.ValidateCertificate)); // Bind the Core property (there's just one) connectionStringBox.DataBindings.Add(nameof(connectionStringBox.Text), vm, nameof(vm.ConnectionString)); + // Bind the SessionType checkboxes + sessionTypeIsPythonButton.DataBindings.Add(nameof(sessionTypeIsPythonButton.Checked), + vm, nameof(vm.SessionTypeIsPython)); + sessionTypeIsGroovyButton.DataBindings.Add(nameof(sessionTypeIsGroovyButton.Checked), + vm, nameof(vm.SessionTypeIsGroovy)); + // Bind the IsDefault property makeDefaultCheckBox.DataBindings.Add(nameof(makeDefaultCheckBox.Checked), vm, nameof(vm.IsDefault)); diff --git a/csharp/ExcelAddIn/views/CredentialsDialog.resx b/csharp/ExcelAddIn/views/CredentialsDialog.resx index b92c16350e8..4f24d55cd6b 100644 --- a/csharp/ExcelAddIn/views/CredentialsDialog.resx +++ b/csharp/ExcelAddIn/views/CredentialsDialog.resx @@ -1,7 +1,7 @@