From 15e26bbf65093de1ba48dcdd90780b1f316eb94c Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Fri, 2 Jun 2023 18:41:50 -0700 Subject: [PATCH 1/4] Add new connection parameter `tunnelHost` to use with tunnel cunnection. Signed-off-by: Yury-Fridlyand --- .../jdbc/config/ConnectionConfig.java | 17 +++++++++++++- .../config/TunnelHostConnectionProperty.java | 19 +++++++++++++++ .../transport/http/ApacheHttpTransport.java | 3 ++- .../AWSRequestSigningApacheInterceptor.java | 23 +++++++++++++++---- ...SRequestSigningApacheInterceptorTests.java | 2 +- 5 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/opensearch/jdbc/config/TunnelHostConnectionProperty.java diff --git a/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java b/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java index b0bbcac..43ff361 100644 --- a/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java +++ b/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java @@ -46,6 +46,7 @@ public class ConnectionConfig { private String trustStoreType; private boolean trustSelfSigned; private boolean hostnameVerification; + private String tunnelHost; private ConnectionConfig(Builder builder) { this.url = builder.getUrl(); @@ -80,6 +81,7 @@ private ConnectionConfig(Builder builder) { this.trustSelfSigned = builder.getTrustSelfSignedConnectionProperty().getValue(); this.hostnameVerification = builder.getHostnameVerificationConnectionProperty().getValue(); + this.tunnelHost = builder.getTunnelHostConnectionProperty().getValue(); } public static Builder builder() { @@ -182,6 +184,10 @@ public boolean hostnameVerification() { return hostnameVerification; } + public String tunnelHost() { + return tunnelHost; + } + @Override public String toString() { return "ConnectionConfig{" + @@ -209,6 +215,7 @@ public String toString() { ", trustStoreType='" + trustStoreType + '\'' + ", trustSelfSigned='" + trustSelfSigned + '\'' + ", hostnameVerification='" + hostnameVerification + '\'' + + ", tunnelHost='" + tunnelHost + '\'' + '}'; } @@ -256,6 +263,9 @@ public static class Builder { private HostnameVerificationConnectionProperty hostnameVerificationConnectionProperty = new HostnameVerificationConnectionProperty(); + private TunnelHostConnectionProperty tunnelHostConnectionProperty + = new TunnelHostConnectionProperty(); + ConnectionProperty[] connectionProperties = new ConnectionProperty[]{ hostProperty, portProperty, @@ -278,7 +288,8 @@ public static class Builder { trustStorePasswordConnectionProperty, trustStoreTypeConnectionProperty, trustSelfSignedConnectionProperty, - hostnameVerificationConnectionProperty + hostnameVerificationConnectionProperty, + tunnelHostConnectionProperty }; private String url = null; @@ -385,6 +396,10 @@ public HostnameVerificationConnectionProperty getHostnameVerificationConnectionP return hostnameVerificationConnectionProperty; } + public TunnelHostConnectionProperty getTunnelHostConnectionProperty() { + return tunnelHostConnectionProperty; + } + public Builder setLogWriter(PrintWriter printWriter) { this.logWriter = printWriter; return this; diff --git a/src/main/java/org/opensearch/jdbc/config/TunnelHostConnectionProperty.java b/src/main/java/org/opensearch/jdbc/config/TunnelHostConnectionProperty.java new file mode 100644 index 0000000..8869ec6 --- /dev/null +++ b/src/main/java/org/opensearch/jdbc/config/TunnelHostConnectionProperty.java @@ -0,0 +1,19 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.jdbc.config; + +public class TunnelHostConnectionProperty extends StringConnectionProperty { + public static final String KEY = "tunnelHost"; + + public TunnelHostConnectionProperty() { + super(KEY); + } + + public String getDefault() { + return "localhost"; + } + +} diff --git a/src/main/java/org/opensearch/jdbc/transport/http/ApacheHttpTransport.java b/src/main/java/org/opensearch/jdbc/transport/http/ApacheHttpTransport.java index 99d1a26..23201e7 100644 --- a/src/main/java/org/opensearch/jdbc/transport/http/ApacheHttpTransport.java +++ b/src/main/java/org/opensearch/jdbc/transport/http/ApacheHttpTransport.java @@ -119,7 +119,8 @@ public ApacheHttpTransport(ConnectionConfig connectionConfig, Logger log, String new AWSRequestSigningApacheInterceptor( "es", signer, - provider)); + provider, + connectionConfig.tunnelHost())); } // TODO - can apply settings retry & backoff diff --git a/src/main/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptor.java b/src/main/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptor.java index 49d8856..9263de5 100644 --- a/src/main/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptor.java +++ b/src/main/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptor.java @@ -7,6 +7,7 @@ package org.opensearch.jdbc.transport.http.auth.aws; import com.amazonaws.DefaultRequest; +import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.Signer; import com.amazonaws.http.HttpMethodName; @@ -53,6 +54,12 @@ public class AWSRequestSigningApacheInterceptor implements HttpRequestIntercepto */ private final AWSCredentialsProvider awsCredentialsProvider; + /** + * Hostname of the OpenSearch cluster, required to make a valid AWS signature in case if + * proxy/tunnel/gateway used. + */ + private final String host; + /** * * @param service service that we're connecting to @@ -61,10 +68,12 @@ public class AWSRequestSigningApacheInterceptor implements HttpRequestIntercepto */ public AWSRequestSigningApacheInterceptor(final String service, final Signer signer, - final AWSCredentialsProvider awsCredentialsProvider) { + final AWSCredentialsProvider awsCredentialsProvider, + final String host) { this.service = service; this.signer = signer; this.awsCredentialsProvider = awsCredentialsProvider; + this.host = host; } /** @@ -83,9 +92,14 @@ public void process(final HttpRequest request, final HttpContext context) // Copy Apache HttpRequest to AWS DefaultRequest DefaultRequest signableRequest = new DefaultRequest<>(service); - HttpHost host = (HttpHost) context.getAttribute(HTTP_TARGET_HOST); - if (host != null) { - signableRequest.setEndpoint(URI.create(host.toURI())); + if (host != null && !host.equals("")) { + // override host if given by user (`tunnelHost` connection parameter) + signableRequest.setEndpoint(URI.create("https://" + host)); + } else { + HttpHost host = (HttpHost) context.getAttribute(HTTP_TARGET_HOST); + if (host != null) { + signableRequest.setEndpoint(URI.create(host.toURI())); + } } final HttpMethodName httpMethod = HttpMethodName.fromValue(request.getRequestLine().getMethod()); @@ -120,6 +134,7 @@ public void process(final HttpRequest request, final HttpContext context) httpEntityEnclosingRequest.setEntity(basicHttpEntity); } } + } /** diff --git a/src/test/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptorTests.java b/src/test/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptorTests.java index ec39e6f..1f4269b 100644 --- a/src/test/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptorTests.java +++ b/src/test/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptorTests.java @@ -97,7 +97,7 @@ private static AWSRequestSigningApacheInterceptor createInterceptor() { new AWSStaticCredentialsProvider(new AnonymousAWSCredentials()); return new AWSRequestSigningApacheInterceptor("servicename", new AddHeaderSigner("Signature", "wuzzle"), - anonymousCredentialsProvider); + anonymousCredentialsProvider, null); } } From a2420db79c74c0633bbb469481398d41be1bd18d Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Mon, 5 Jun 2023 17:37:47 -0700 Subject: [PATCH 2/4] Make property key names case insensitive. Update doc and other misc fixes. Signed-off-by: Yury-Fridlyand --- README.md | 179 +++++++++--------- .../jdbc/config/ConnectionConfig.java | 3 +- .../jdbc/config/HostConnectionProperty.java | 10 +- .../config/TunnelHostConnectionProperty.java | 2 +- .../jdbc/internal/util/UrlParser.java | 12 +- .../AWSRequestSigningApacheInterceptor.java | 2 +- 6 files changed, 106 insertions(+), 102 deletions(-) diff --git a/README.md b/README.md index e31356c..b774e26 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ To setup a connection, the driver requires a JDBC connection URL. The connection * host - Hostname or IP address of the target cluster. Default is *localhost*. + Hostname or IP address of the target cluster. Default is *localhost*. * port @@ -61,37 +61,38 @@ To setup a connection, the driver requires a JDBC connection URL. The connection * property key=value The query string portion of the connection URL can contain desired connection settings in the form of one or more - *property-key=value* pairs. The possible configuration properties are provided in the table below. The property keys are case sensitive but values are not unless otherwise indicated. + *property-key=value* pairs. The possible configuration properties are provided in the table below. The property keys and values are case insensitive and values unless otherwise indicated. Note that JDBC provides multiple APIs for specifying connection properties of which specifying them in the connection URL is just one. When directly coding with the driver you can choose any of the other options (refer sample code below). If you are setting up a connection via a tool, it is likely the tool will allow you to specify the - connection URL with just the scheme, host, port and context-path components) while the the connection properties are provided separately. + connection URL (with just the scheme, host, port and context-path components) while the the connection properties are provided separately. For example, you may not wish to place the user and password in the connection URL. Check the tool you are using for such support. The configurable connection properties are: - | Property Key | Description | Accepted Value(s) | Default value | - | ------------- |-------------| -----|---------| - | user | Connection username. mandatory if `auth` property selects a authentication scheme that mandates a username value | any string | `null` | - | password | Connection password. mandatory if `auth` property selects a authentication scheme that mandates a password value | any string | `null` | - | fetchSize | Cursor page size | positive integer value. Max value is limited by `index.max_result_window` OpenSearch setting | `0` (for non-paginated response) | - | logOutput | location where driver logs should be emitted | a valid file path | `null` (logs are disabled) | - | logLevel | severity level for which driver logs should be emitted | in order from highest(least logging) to lowest(most logging): OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL | OFF (logs are disabled) | - | auth | authentication mechanism to use | `NONE` (no auth), `BASIC` (HTTP Basic), `AWS_SIGV4` (AWS SIGV4) | `basic` if username and/or password is specified, `NONE` otherwise | - | awsCredentialsProvider | The AWS credential provider to be used when authentication mechanism is `AWS_SIGV4` (AWS SIGV4). If not set, the driver will use DefaultAWSCredentialsProviderChain to sign the request. Note that the driver renamed the namespaces of its dependencies, so the value has to be an instance of com.amazonaws.opensearch.sql.jdbc.shadow.com.amazonaws.auth.AWSCredentialsProvider| Instance of an AWSCredentialProvider | DefaultAWSCredentialsProviderChain | - | region | if authentication type is `aws_sigv4`, then this is the region value to use when signing requests. Only needed if the driver can not determine the region for the host endpoint. The driver will detect the region if the host endpoint matches a known url pattern. | a valid AWS region value e.g. us-east-1 | `null` (auto-detected if possible from the host endpoint) | - | requestCompression | whether to indicate acceptance of compressed (gzip) responses when making server requests | `true` or `false` | `false` | - | useSSL | whether to establish the connection over SSL/TLS | `true` or `false` | `false` if scheme is `http`, `true` if scheme is `https` | - | trustStoreLocation | location of the SSL/TLS truststore to use | file path or URL as appropriate to the type of truststore | `null` | - | trustStoreType | type of the truststore | valid truststore type recognized by available Java security providers | JKS | - | trustStorePassword | password to access the Trust Store | any string | `null` | - | keyStoreLocation | location of the SSL/TLS keystore to use | file path or URL as appropriate to the type of keystore | `null` | - | keyStoreType | type of the keystore | valid keystore type recognized by available Java security providers | JKS | - | keyStorePassword | password to access the keystore | any string | `null` | - | trustSelfSigned | shortcut way to indicate that any self-signed certificate should be accepted. A truststore is not required to be configured. | `true` or `false` | `false` | - | hostnameVerification | indicate whether certificate hostname verification should be performed when using SSL/TLS | `true` or `false` | `true` | + | Property Key | Description | Accepted Value(s) | Default value | + |------------------------|------------------------------------------------------------------------------------------------------------------|-------------------|----------------| + | user | Connection username. mandatory if `auth` property selects a authentication scheme that mandates a username value | any string | `null` | + | password | Connection password. mandatory if `auth` property selects a authentication scheme that mandates a password value | any string | `null` | + | fetchSize | Cursor page size | positive integer value. Max value is limited by `index.max_result_window` OpenSearch setting | `0` (for non-paginated response) | + | logOutput | Location where driver logs should be emitted | a valid file path | `null` (logs are disabled) | + | logLevel | Severity level for which driver logs should be emitted | in order from highest (least logging) to lowest (most logging): `OFF`, `FATAL`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`, `ALL` | `OFF` (logs are disabled) | + | auth | Authentication mechanism to use | `NONE` (no auth), `BASIC` (HTTP Basic), `AWS_SIGV4` (AWS SIGV4) | `basic` if username and/or password is specified, `NONE` otherwise | + | awsCredentialsProvider | The AWS credential provider to be used when authentication mechanism is `AWS_SIGV4` (AWS SIGV4). If not set, the driver will use `DefaultAWSCredentialsProviderChain` to sign the request. The value has to be an instance of `com.amazonaws.auth.AWSCredentialsProvider` | Instance of an `AWSCredentialProvider` | `DefaultAWSCredentialsProviderChain` | + | region | If authentication type is `aws_sigv4`, then this is the region value to use when signing requests. Only needed if the driver can not determine the region for the host endpoint. The driver will detect the region if the host endpoint matches a known url pattern. | a valid AWS region value e.g. `us-east-1` | `null` (auto-detected if possible from the host endpoint) | + | requestCompression | Whether to indicate acceptance of compressed (gzip) responses when making server requests | `true` or `false` | `false` | + | useSSL | Whether to establish the connection over SSL/TLS | `true` or `false` | `false` if scheme is `http`, `true` if scheme is `https` | + | trustStoreLocation | Location of the SSL/TLS truststore to use | file path or URL as appropriate to the type of truststore | `null` | + | trustStoreType | Type of the truststore | valid truststore type recognized by available Java security providers | JKS | + | trustStorePassword | Password to access the Trust Store | any string | `null` | + | keyStoreLocation | Location of the SSL/TLS keystore to use | file path or URL as appropriate to the type of keystore | `null` | + | keyStoreType | Type of the keystore | valid keystore type recognized by available Java security providers | JKS | + | keyStorePassword | Password to access the keystore | any string | `null` | + | trustSelfSigned | Shortcut way to indicate that any self-signed certificate should be accepted. A truststore is not required to be configured. | `true` or `false` | `false` | + | hostnameVerification | Indicate whether certificate hostname verification should be performed when using SSL/TLS | `true` or `false` | `true` | + | tunnelHost | VPC endpoint hostname if connected through a tunnel or proxy and `AWS_SIGV4` authentication is used | any string | `null` | ### Connecting using the DriverManager interface @@ -105,15 +106,15 @@ Code samples to open a connection for some typical scenarios are given below: import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://localhost:9200"; Connection con = DriverManager.getConnection(url); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -124,15 +125,15 @@ con.close(); import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://https://remote-host-name"; Connection con = DriverManager.getConnection(url); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -143,8 +144,8 @@ or, import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://remote-host-name"; Properties properties = new Properties(); @@ -152,9 +153,9 @@ properties.put("useSSL", "true"); Connection con = DriverManager.getConnection(url, properties); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -165,17 +166,17 @@ con.close(); import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://https://remote-host-name"; String user = "username"; String password = "password"; Connection con = DriverManager.getConnection(url, user, password); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -186,8 +187,8 @@ or, import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://remote-host-name"; Properties properties = new Properties(); @@ -197,9 +198,9 @@ properties.put("password", "password"); Connection con = DriverManager.getConnection(url, properties); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -210,8 +211,8 @@ con.close(); import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://remote-host-name"; Properties properties = new Properties(); @@ -226,9 +227,9 @@ properties.put("password", "password"); Connection con = DriverManager.getConnection(url, properties); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -239,15 +240,15 @@ con.close(); import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://https://remote-host-name?auth=aws_sigv4"; Connection con = DriverManager.getConnection(url); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -258,8 +259,8 @@ or, import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://https://remote-host-name"; Properties properties = new Properties(); @@ -267,9 +268,9 @@ properties.put("auth", "aws_sigv4"); Connection con = DriverManager.getConnection(url, properties); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -280,8 +281,8 @@ con.close(); import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://https://remote-host-name"; Properties properties = new Properties(); @@ -289,9 +290,9 @@ properties.put("awsCredentialsProvider", new EnvironmentVariableCredentialsProvi Connection con = DriverManager.getConnection(url, properties); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -302,15 +303,15 @@ con.close(); import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://https://remote-host-name?auth=aws_sigv4®ion=us-west-1"; Connection con = DriverManager.getConnection(url); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -321,8 +322,8 @@ or, import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; -. -. + + String url = "jdbc:opensearch://https://remote-host-name"; Properties properties = new Properties(); @@ -331,15 +332,15 @@ properties.put("region", "us-west-2"); Connection con = DriverManager.getConnection(url, properties); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` ### Connecting using the DataSource interface -The driver also provides a javax.sql.DataSource implementation via the `org.opensearch.jdbc.OpenSearchDataSource` class that can be used to obtain a connection. Here are some typical code samples: +The driver also provides a `javax.sql.DataSource` implementation via the `org.opensearch.jdbc.OpenSearchDataSource` class that can be used to obtain a connection. Here are some typical code samples: * Connect to localhost on port 9200 with no authentication over a plain connection @@ -351,8 +352,7 @@ import javax.sql.DataSource; import org.opensearch.jdbc.OpenSearchDataSource; -. -. + String url = "jdbc:opensearch://localhost:9200"; OpenSearchDataSource ds = new OpenSearchDataSource(); @@ -360,9 +360,9 @@ ds.setUrl(url); Connection con = ds.getConnection(url); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -376,8 +376,7 @@ import javax.sql.DataSource; import org.opensearch.jdbc.OpenSearchDataSource; -. -. + String url = "jdbc:opensearch://https://remote-host-name"; OpenSearchDataSource ds = new OpenSearchDataSource(); @@ -385,9 +384,9 @@ ds.setUrl(url); Connection con = ds.getConnection(url); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -401,8 +400,7 @@ import javax.sql.DataSource; import org.opensearch.jdbc.OpenSearchDataSource; -. -. + String url = "jdbc:opensearch://https://remote-host-name"; OpenSearchDataSource ds = new OpenSearchDataSource(); @@ -410,9 +408,9 @@ ds.setUrl(url); Connection con = ds.getConnection(url, "user", "password"); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -426,8 +424,7 @@ import javax.sql.DataSource; import org.opensearch.jdbc.OpenSearchDataSource; -. -. + String url = "jdbc:opensearch://https://remote-host-name?auth=aws_sigv4"; OpenSearchDataSource ds = new OpenSearchDataSource(); @@ -435,9 +432,9 @@ ds.setUrl(url); Connection con = ds.getConnection(url); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -451,8 +448,7 @@ import javax.sql.DataSource; import org.opensearch.jdbc.OpenSearchDataSource; -. -. + String url = "jdbc:opensearch://https://remote-host-name?auth=aws_sigv4®ion=us-west-1"; OpenSearchDataSource ds = new OpenSearchDataSource(); @@ -461,9 +457,9 @@ ds.setAwsCredentialProvider(new EnvironmentVariableCredentialsProvider()); Connection con = ds.getConnection(url); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` @@ -477,8 +473,7 @@ import javax.sql.DataSource; import org.opensearch.jdbc.OpenSearchDataSource; -. -. + String url = "jdbc:opensearch://https://remote-host-name?auth=aws_sigv4®ion=us-west-1"; OpenSearchDataSource ds = new OpenSearchDataSource(); @@ -486,9 +481,9 @@ ds.setUrl(url); Connection con = ds.getConnection(url); Statement st = con.createStatement(); -. + // use the connection -. + // close connection con.close(); ``` diff --git a/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java b/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java index 43ff361..2f23c63 100644 --- a/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java +++ b/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java @@ -450,7 +450,7 @@ public Builder setProperties(Properties properties) { while (enumeration.hasMoreElements()) { String key = (String) enumeration.nextElement(); - this.properties.setProperty(key, properties.getProperty(key)); + this.properties.setProperty(key.toLowerCase(), properties.getProperty(key)); } } return this; @@ -559,6 +559,7 @@ private void validateConfig() throws ConnectionPropertyException { * @return effective value */ private Object getPropertyValueToSet(String key) { + key = key.toLowerCase(); if (overrideMap != null && overrideMap.containsKey(key)) { return overrideMap.get(key); } diff --git a/src/main/java/org/opensearch/jdbc/config/HostConnectionProperty.java b/src/main/java/org/opensearch/jdbc/config/HostConnectionProperty.java index 7c6af4f..127578f 100644 --- a/src/main/java/org/opensearch/jdbc/config/HostConnectionProperty.java +++ b/src/main/java/org/opensearch/jdbc/config/HostConnectionProperty.java @@ -6,6 +6,8 @@ package org.opensearch.jdbc.config; +import java.net.URI; + public class HostConnectionProperty extends StringConnectionProperty { public static final String KEY = "host"; @@ -13,8 +15,14 @@ public HostConnectionProperty() { super(KEY); } + @Override + protected String parseValue(Object value) throws ConnectionPropertyException { + String host = value.toString(); + // URI class extracts host from the string. It requires a prefix to be set to parse it properly. + return URI.create(host.startsWith("http") ? host : "https://" + host).getHost(); + } + public String getDefault() { return "localhost"; } - } diff --git a/src/main/java/org/opensearch/jdbc/config/TunnelHostConnectionProperty.java b/src/main/java/org/opensearch/jdbc/config/TunnelHostConnectionProperty.java index 8869ec6..64a6423 100644 --- a/src/main/java/org/opensearch/jdbc/config/TunnelHostConnectionProperty.java +++ b/src/main/java/org/opensearch/jdbc/config/TunnelHostConnectionProperty.java @@ -13,7 +13,7 @@ public TunnelHostConnectionProperty() { } public String getDefault() { - return "localhost"; + return null; } } diff --git a/src/main/java/org/opensearch/jdbc/internal/util/UrlParser.java b/src/main/java/org/opensearch/jdbc/internal/util/UrlParser.java index 4db9eb8..916c4b4 100644 --- a/src/main/java/org/opensearch/jdbc/internal/util/UrlParser.java +++ b/src/main/java/org/opensearch/jdbc/internal/util/UrlParser.java @@ -84,18 +84,18 @@ public static Properties parseProperties(final String inputUrl) throws URISyntax String path = uri.getPath(); if (host != null) - props.setProperty(HostConnectionProperty.KEY, host); + props.setProperty(HostConnectionProperty.KEY.toLowerCase(), host); if (port != -1) - props.setProperty(PortConnectionProperty.KEY, Integer.toString(port)); + props.setProperty(PortConnectionProperty.KEY.toLowerCase(), Integer.toString(port)); if (path != null && path.length() > 0) - props.setProperty(PathConnectionProperty.KEY, path); + props.setProperty(PathConnectionProperty.KEY.toLowerCase(), path); if ("https".equalsIgnoreCase(scheme)) { - props.setProperty(UseSSLConnectionProperty.KEY, "true"); + props.setProperty(UseSSLConnectionProperty.KEY.toLowerCase(), "true"); } else if ("http".equalsIgnoreCase(scheme)) { - props.setProperty(UseSSLConnectionProperty.KEY, "false"); + props.setProperty(UseSSLConnectionProperty.KEY.toLowerCase(), "false"); } else { throw new URISyntaxException(inputUrl, "Invalid scheme:"+scheme+". Only http and https are supported."); } @@ -114,7 +114,7 @@ public static Properties parseProperties(final String inputUrl) throws URISyntax + kv[0] + ". Expected key=value pairs"); } else { - props.setProperty(kv[0], kv[1]); + props.setProperty(kv[0].toLowerCase(), kv[1]); } } } diff --git a/src/main/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptor.java b/src/main/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptor.java index 9263de5..2ebdf0d 100644 --- a/src/main/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptor.java +++ b/src/main/java/org/opensearch/jdbc/transport/http/auth/aws/AWSRequestSigningApacheInterceptor.java @@ -94,7 +94,7 @@ public void process(final HttpRequest request, final HttpContext context) if (host != null && !host.equals("")) { // override host if given by user (`tunnelHost` connection parameter) - signableRequest.setEndpoint(URI.create("https://" + host)); + signableRequest.setEndpoint(URI.create(host.startsWith("http") ? host : "https://" + host)); } else { HttpHost host = (HttpHost) context.getAttribute(HTTP_TARGET_HOST); if (host != null) { From 0adb53759b7080a27d1df352459c07ff9b9e04ae Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Mon, 5 Jun 2023 19:12:49 -0700 Subject: [PATCH 3/4] Fix tests. Signed-off-by: Yury-Fridlyand --- .../org/opensearch/jdbc/config/ConnectionConfig.java | 12 +++++++++--- .../jdbc/config/HostConnectionProperty.java | 4 ++-- .../java/org/opensearch/jdbc/test/KeyValuePairs.java | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java b/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java index 2f23c63..9a69623 100644 --- a/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java +++ b/src/main/java/org/opensearch/jdbc/config/ConnectionConfig.java @@ -416,8 +416,12 @@ public Builder setUrl(String url) { public Builder setPropertyMap(Map map) { if (map != null) { - propertyMap = new HashMap<>(); - propertyMap.putAll(map); + if (propertyMap == null) { + propertyMap = new HashMap<>(); + } + for (Map.Entry pair : map.entrySet()) { + propertyMap.put(pair.getKey().toLowerCase(), pair.getValue()); + } } return this; } @@ -437,7 +441,9 @@ public Builder overrideProperties(Map map) { if (overrideMap == null) { overrideMap = new HashMap<>(); } - this.overrideMap.putAll(map); + for (Map.Entry pair : map.entrySet()) { + overrideMap.put(pair.getKey().toLowerCase(), pair.getValue()); + } } return this; } diff --git a/src/main/java/org/opensearch/jdbc/config/HostConnectionProperty.java b/src/main/java/org/opensearch/jdbc/config/HostConnectionProperty.java index 127578f..cbe8634 100644 --- a/src/main/java/org/opensearch/jdbc/config/HostConnectionProperty.java +++ b/src/main/java/org/opensearch/jdbc/config/HostConnectionProperty.java @@ -17,9 +17,9 @@ public HostConnectionProperty() { @Override protected String parseValue(Object value) throws ConnectionPropertyException { - String host = value.toString(); + String host = super.parseValue(value); // URI class extracts host from the string. It requires a prefix to be set to parse it properly. - return URI.create(host.startsWith("http") ? host : "https://" + host).getHost(); + return URI.create(host.startsWith("http") ? host : "https://" + host).getAuthority(); } public String getDefault() { diff --git a/src/test/java/org/opensearch/jdbc/test/KeyValuePairs.java b/src/test/java/org/opensearch/jdbc/test/KeyValuePairs.java index 2955fcd..eb1f4e5 100644 --- a/src/test/java/org/opensearch/jdbc/test/KeyValuePairs.java +++ b/src/test/java/org/opensearch/jdbc/test/KeyValuePairs.java @@ -36,7 +36,7 @@ public StringKvp(String key, String value) { public static Properties toProperties(final StringKvp... kvps) { Properties props = new Properties(); - Arrays.stream(kvps).forEach(kvp -> props.setProperty(kvp.getKey(), kvp.getValue())); + Arrays.stream(kvps).forEach(kvp -> props.setProperty(kvp.getKey().toLowerCase(), kvp.getValue())); return props; } From 979c258cdd42e955a05b421a9e160e659f5a0f78 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Fri, 16 Jun 2023 09:46:20 -0700 Subject: [PATCH 4/4] Update README.md Co-authored-by: Matthew Wells Signed-off-by: Yury-Fridlyand --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b774e26..478a2f8 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ To setup a connection, the driver requires a JDBC connection URL. The connection | logOutput | Location where driver logs should be emitted | a valid file path | `null` (logs are disabled) | | logLevel | Severity level for which driver logs should be emitted | in order from highest (least logging) to lowest (most logging): `OFF`, `FATAL`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`, `ALL` | `OFF` (logs are disabled) | | auth | Authentication mechanism to use | `NONE` (no auth), `BASIC` (HTTP Basic), `AWS_SIGV4` (AWS SIGV4) | `basic` if username and/or password is specified, `NONE` otherwise | - | awsCredentialsProvider | The AWS credential provider to be used when authentication mechanism is `AWS_SIGV4` (AWS SIGV4). If not set, the driver will use `DefaultAWSCredentialsProviderChain` to sign the request. The value has to be an instance of `com.amazonaws.auth.AWSCredentialsProvider` | Instance of an `AWSCredentialProvider` | `DefaultAWSCredentialsProviderChain` | + | awsCredentialsProvider | The AWS credential provider to be used when authentication mechanism is `AWS_SIGV4` (AWS SIGV4). If not set, the driver will use `DefaultAWSCredentialsProviderChain` to sign the request. The value has to be an instance of `com.amazonaws.auth.AWSCredentialsProvider` | instance of an `AWSCredentialProvider` | `DefaultAWSCredentialsProviderChain` | | region | If authentication type is `aws_sigv4`, then this is the region value to use when signing requests. Only needed if the driver can not determine the region for the host endpoint. The driver will detect the region if the host endpoint matches a known url pattern. | a valid AWS region value e.g. `us-east-1` | `null` (auto-detected if possible from the host endpoint) | | requestCompression | Whether to indicate acceptance of compressed (gzip) responses when making server requests | `true` or `false` | `false` | | useSSL | Whether to establish the connection over SSL/TLS | `true` or `false` | `false` if scheme is `http`, `true` if scheme is `https` |