From 9b14d13af86d80dd91785e5b6cbe78a5662f08aa Mon Sep 17 00:00:00 2001 From: Anagh Hegde Date: Wed, 3 Apr 2024 20:04:49 +0530 Subject: [PATCH] feat: add form config for reading certs for PG (#31895) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Form config changes for the PG datasource to support reading certs from user Fixes #31400 ## Automation /ok-to-test tags="tag.Datasource" ### :mag: Cypress test results > [!IMPORTANT] > Workflow run: > Commit: `0fb57fe78e973db8a3df5f2e407b85eef4adb4e2` > Cypress dashboard url: Click here! > All cypress tests have passed 🎉🎉🎉 ## Summary by CodeRabbit - **New Features** - Enhanced SSL configuration options for database connections, including support for client and server CA certificate files. - **Refactor** - Improved handling and encoding of SSL certificate content for database connections, ensuring compatibility and security. --------- Co-authored-by: Aman Agarwal Co-authored-by: Rishabh-Rathod --- .../appsmith/external/models/SSLDetails.java | 6 + .../com/external/plugins/PostgresPlugin.java | 37 ++-- .../utils/MutualTLSCertValidatingFactory.java | 5 +- .../src/main/resources/form.json | 178 +++++++++++++++--- .../ApplicationForkingServiceTests.java | 6 + 5 files changed, 187 insertions(+), 45 deletions(-) diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/SSLDetails.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/SSLDetails.java index b1700d4dc1..517090df0b 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/SSLDetails.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/SSLDetails.java @@ -68,6 +68,12 @@ public class SSLDetails implements AppsmithDomain { UploadedFile caCertificateFile; + UploadedFile clientCACertificateFile; + + UploadedFile clientKeyCertificateFile; + + UploadedFile serverCACertificateFile; + Boolean usePemCertificate; PEMCertificate pemCertificate; diff --git a/app/server/appsmith-plugins/postgresPlugin/src/main/java/com/external/plugins/PostgresPlugin.java b/app/server/appsmith-plugins/postgresPlugin/src/main/java/com/external/plugins/PostgresPlugin.java index 79c49916c0..803efdeef7 100644 --- a/app/server/appsmith-plugins/postgresPlugin/src/main/java/com/external/plugins/PostgresPlugin.java +++ b/app/server/appsmith-plugins/postgresPlugin/src/main/java/com/external/plugins/PostgresPlugin.java @@ -51,6 +51,7 @@ import reactor.core.scheduler.Schedulers; import java.io.IOException; import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; import java.sql.Array; import java.sql.Connection; import java.sql.Date; @@ -1199,25 +1200,31 @@ public class PostgresPlugin extends BasePlugin { config.addDataSourceProperty("sslfactory", MutualTLSCertValidatingFactory.class.getName()); config.addDataSourceProperty( "clientCertString", - datasourceConfiguration - .getConnection() - .getSsl() - .getCertificateFile() - .getBase64Content()); + new String( + datasourceConfiguration + .getConnection() + .getSsl() + .getClientCACertificateFile() + .getDecodedContent(), + StandardCharsets.UTF_8)); config.addDataSourceProperty( "clientKeyString", - datasourceConfiguration - .getConnection() - .getSsl() - .getKeyFile() - .getBase64Content()); + new String( + datasourceConfiguration + .getConnection() + .getSsl() + .getClientKeyCertificateFile() + .getDecodedContent(), + StandardCharsets.UTF_8)); config.addDataSourceProperty( "serverCACertString", - datasourceConfiguration - .getConnection() - .getSsl() - .getCaCertificateFile() - .getBase64Content()); + new String( + datasourceConfiguration + .getConnection() + .getSsl() + .getServerCACertificateFile() + .getDecodedContent(), + StandardCharsets.UTF_8)); break; diff --git a/app/server/appsmith-plugins/postgresPlugin/src/main/java/com/external/plugins/utils/MutualTLSCertValidatingFactory.java b/app/server/appsmith-plugins/postgresPlugin/src/main/java/com/external/plugins/utils/MutualTLSCertValidatingFactory.java index 8c0ddfb40a..571b852d4e 100644 --- a/app/server/appsmith-plugins/postgresPlugin/src/main/java/com/external/plugins/utils/MutualTLSCertValidatingFactory.java +++ b/app/server/appsmith-plugins/postgresPlugin/src/main/java/com/external/plugins/utils/MutualTLSCertValidatingFactory.java @@ -7,6 +7,7 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.security.PrivateKey; import java.security.SecureRandom; @@ -23,7 +24,7 @@ public class MutualTLSCertValidatingFactory extends WrappedFactory { // Client certificate ByteArrayInputStream clientCertIS = - new ByteArrayInputStream(Base64.getDecoder().decode(info.getProperty("clientCertString"))); + new ByteArrayInputStream(info.getProperty("clientCertString").getBytes(StandardCharsets.UTF_8)); X509Certificate clientCertificate = (X509Certificate) cf.generateCertificate(clientCertIS); // Client key and this assumes we are using RSA keys @@ -39,7 +40,7 @@ public class MutualTLSCertValidatingFactory extends WrappedFactory { // CA certificate for verifying the server ByteArrayInputStream caCertIS = - new ByteArrayInputStream(Base64.getDecoder().decode(info.getProperty("serverCACertString"))); + new ByteArrayInputStream(info.getProperty("serverCACertString").getBytes(StandardCharsets.UTF_8)); X509Certificate caCertificate = (X509Certificate) cf.generateCertificate(caCertIS); // Client keystore diff --git a/app/server/appsmith-plugins/postgresPlugin/src/main/resources/form.json b/app/server/appsmith-plugins/postgresPlugin/src/main/resources/form.json index 3a8fecaa11..4ae416e63a 100644 --- a/app/server/appsmith-plugins/postgresPlugin/src/main/resources/form.json +++ b/app/server/appsmith-plugins/postgresPlugin/src/main/resources/form.json @@ -10,14 +10,8 @@ "controlType": "SEGMENTED_CONTROL", "initialValue": "READ_WRITE", "options": [ - { - "label": "Read / Write", - "value": "READ_WRITE" - }, - { - "label": "Read only", - "value": "READ_ONLY" - } + { "label": "Read / Write", "value": "READ_WRITE" }, + { "label": "Read only", "value": "READ_ONLY" } ] }, { @@ -84,27 +78,155 @@ "controlType": "DROP_DOWN", "initialValue": "DEFAULT", "options": [ - { - "label": "Default", - "value": "DEFAULT" - }, - { - "label": "Allow", - "value": "ALLOW" - }, - { - "label": "Prefer", - "value": "PREFER" - }, - { - "label": "Require", - "value": "REQUIRE" - }, - { - "label": "Disable", - "value": "DISABLE" - } + { "label": "Default", "value": "DEFAULT" }, + { "label": "Allow", "value": "ALLOW" }, + { "label": "Prefer", "value": "PREFER" }, + { "label": "Require", "value": "REQUIRE" }, + { "label": "Disable", "value": "DISABLE" }, + { "label": "Verify CA", "value": "VERIFY_CA" }, + { "label": "Verify Full", "value": "VERIFY_FULL" } ] + }, + { + "label": "Certificate Type", + "configProperty": "datasourceConfiguration.connection.ssl.certificateType", + "controlType": "DROP_DOWN", + "initialValue": "-Select-", + "options": [ + { "label": "Upload File", "value": "FILE" }, + { "label": "Base64 String", "value": "BASE64_STRING" } + ], + "hidden": { + "conditionType": "AND", + "conditions": [ + { + "path": "datasourceConfiguration.connection.ssl.authType", + "comparison": "NOT_EQUALS", + "value": "VERIFY_CA" + }, + { + "path": "datasourceConfiguration.connection.ssl.authType", + "comparison": "NOT_EQUALS", + "value": "VERIFY_FULL" + } + ] + } + }, + { + "sectionStyles": { "display": "flex", "flex-wrap": "wrap" }, + "children": [ + { + "sectionStyles": { "marginRight": "10px" }, + "children": [ + { + "label": "Client CA Certificate File", + "configProperty": "datasourceConfiguration.connection.ssl.clientCACertificateFile", + "controlType": "FILE_PICKER", + "encrypted": true, + "hidden": { + "path": "datasourceConfiguration.connection.ssl.certificateType", + "comparison": "NOT_EQUALS", + "value": "FILE" + } + }, + { + "label": "Client CA Certificate String", + "configProperty": "datasourceConfiguration.connection.ssl.clientCACertificateFile.base64Content", + "controlType": "INPUT_TEXT", + "dataType": "PASSWORD", + "encrypted": true, + "hidden": { + "path": "datasourceConfiguration.connection.ssl.certificateType", + "comparison": "NOT_EQUALS", + "value": "BASE64_STRING" + } + } + ] + }, + { + "sectionStyles": { "marginRight": "10px" }, + "children": [ + { + "label": "Server CA Certificate File", + "configProperty": "datasourceConfiguration.connection.ssl.serverCACertificateFile", + "controlType": "FILE_PICKER", + "encrypted": true, + "hidden": { + "path": "datasourceConfiguration.connection.ssl.certificateType", + "comparison": "NOT_EQUALS", + "value": "FILE" + } + }, + { + "label": "Server CA Certificate String", + "configProperty": "datasourceConfiguration.connection.ssl.serverCACertificateFile.Base64Content", + "controlType": "INPUT_TEXT", + "dataType": "PASSWORD", + "encrypted": true, + "hidden": { + "path": "datasourceConfiguration.connection.ssl.certificateType", + "comparison": "NOT_EQUALS", + "value": "BASE64_STRING" + } + } + ] + }, + { + "sectionStyles": { "marginRight": "10px" }, + "children": [ + { + "label": "Client Key Certificate File", + "configProperty": "datasourceConfiguration.connection.ssl.clientKeyCertificateFile", + "controlType": "FILE_PICKER", + "encrypted": true, + "hidden": { + "path": "datasourceConfiguration.connection.ssl.certificateType", + "comparison": "NOT_EQUALS", + "value": "FILE" + } + }, + { + "label": "Client Key Certificate String", + "configProperty": "datasourceConfiguration.connection.ssl.clientKeyCertificateFile.Base64Content", + "controlType": "INPUT_TEXT", + "dataType": "PASSWORD", + "encrypted": true, + "hidden": { + "path": "datasourceConfiguration.connection.ssl.certificateType", + "comparison": "NOT_EQUALS", + "value": "BASE64_STRING" + } + } + ] + }, + { + "sectionStyles": { "flex": 1 }, + "children": [] + }, + { + "sectionStyles": { "flex": 1 }, + "children": [] + }, + { + "sectionStyles": { "flex": 1 }, + "children": [] + } + ], + "hidden": { + "conditionType": "AND", + "conditions": [ + { + "path": "datasourceConfiguration.connection.ssl.authType", + "comparison": "NOT_EQUALS", + "value": "VERIFY_CA" + }, + { + "path": "datasourceConfiguration.connection.ssl.authType", + "comparison": "NOT_EQUALS", + "value": "VERIFY_FULL" + } + ] + } } ] } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java index 7f2a4bb618..80589d51c5 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java @@ -1455,6 +1455,9 @@ public class ApplicationForkingServiceTests { new UploadedFile("keyFile", "key file content"), new UploadedFile("certFile", "cert file content"), new UploadedFile("caCertFile", "caCert file content"), + new UploadedFile("keyFile", "key file content"), + new UploadedFile("certFile", "cert file content"), + new UploadedFile("caCertFile", "caCert file content"), true, new PEMCertificate( new UploadedFile("pemCertFile", "pem cert file content"), @@ -1684,6 +1687,9 @@ public class ApplicationForkingServiceTests { new UploadedFile("keyFile", "key file content"), new UploadedFile("certFile", "cert file content"), new UploadedFile("caCertFile", "caCert file content"), + new UploadedFile("keyFile", "key file content"), + new UploadedFile("certFile", "cert file content"), + new UploadedFile("caCertFile", "caCert file content"), true, new PEMCertificate( new UploadedFile("pemCertFile", "pem cert file content"),