Skip to content

Commit

Permalink
[CLI] Add flag to disable certificate verification
Browse files Browse the repository at this point in the history
Cherry-pick of trinodb/trino@1c5b9215a2d1b04b5f84e2b3e86

with minor modifications for Presto

Co-authored-by: Lewuathe <[email protected]>
  • Loading branch information
2 people authored and tdcmeehan committed Oct 8, 2024
1 parent 64be0e3 commit 96c58c9
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,13 @@ public class ClientOptions

@Option(name = "--truststore-type", title = "truststore type", description = "Truststore type")
public String trustStoreType = KeyStore.getDefaultType();

@Option(name = "--access-token", title = "access token", description = "Access token")
public String accessToken;

@Option(name = "--insecure", title = "trust all certificates", description = "Skip validation of HTTP server certificates (should only be used for debugging)")
public boolean insecure;

@Option(name = "--user", title = "user", description = "Username")
public String user = System.getProperty("user.name");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ public boolean run()
Optional.ofNullable(clientOptions.truststorePassword),
Optional.ofNullable(clientOptions.trustStoreType),
Optional.ofNullable(clientOptions.accessToken),
clientOptions.insecure,
Optional.ofNullable(clientOptions.user),
clientOptions.password ? Optional.of(getPassword()) : Optional.empty(),
Optional.ofNullable(clientOptions.krb5Principal),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package com.facebook.presto.cli;

import com.facebook.presto.client.ClientSession;
import com.facebook.presto.client.OkHttpUtil;
import com.facebook.presto.client.StatementClient;
import com.google.common.net.HostAndPort;
import okhttp3.OkHttpClient;
Expand Down Expand Up @@ -63,6 +64,7 @@ public QueryRunner(
Optional<String> truststorePassword,
Optional<String> trustStoreType,
Optional<String> accessToken,
boolean insecureSsl,
Optional<String> user,
Optional<String> password,
Optional<String> kerberosPrincipal,
Expand All @@ -77,7 +79,12 @@ public QueryRunner(
this.debug = debug;
this.runtime = runtime;

this.sslSetup = builder -> setupSsl(builder, keystorePath, keystorePassword, keyStoreType, truststorePath, truststorePassword, trustStoreType);
if (insecureSsl) {
this.sslSetup = OkHttpUtil::setupInsecureSsl;
}
else {
this.sslSetup = builder -> setupSsl(builder, keystorePath, keystorePassword, keyStoreType, truststorePath, truststorePassword, trustStoreType);
}

OkHttpClient.Builder builder = new OkHttpClient.Builder();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,19 @@ protected MockResponse createMockResponse()

protected void executeQueries(List<String> queries)
{
Console console = new Console();
QueryRunner queryRunner = createQueryRunner(createMockClientSession());
executeQueries(queryRunner, queries);
}

protected void executeQueries(QueryRunner queryRunner, List<String> queries)
{
Console console = new Console();
for (String query : queries) {
console.executeCommand(queryRunner, query, CSV, false);
}
}

protected static QueryRunner createQueryRunner(ClientSession clientSession)
protected static QueryRunner createQueryRunner(ClientSession clientSession, boolean insecureSsl)
{
return new QueryRunner(
clientSession,
Expand All @@ -136,6 +141,7 @@ protected static QueryRunner createQueryRunner(ClientSession clientSession)
Optional.empty(),
Optional.empty(),
Optional.empty(),
insecureSsl,
Optional.empty(),
Optional.empty(),
Optional.empty(),
Expand All @@ -147,6 +153,11 @@ protected static QueryRunner createQueryRunner(ClientSession clientSession)
true);
}

protected static QueryRunner createQueryRunner(ClientSession clientSession)
{
return createQueryRunner(clientSession, false);
}

protected static void assertHeaders(String headerName, Headers headers, Set<String> expectedSessionHeaderValues)
{
assertEquals(ImmutableSet.copyOf(headers.values(headerName)), expectedSessionHeaderValues);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.presto.cli;

import com.google.common.collect.ImmutableList;
import okhttp3.mockwebserver.MockWebServer;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import static com.google.common.io.Resources.getResource;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.testng.Assert.assertEquals;

@Test(singleThreaded = true)
public class TestInsecureQueryRunner
extends AbstractCliTest
{
@Override
@BeforeMethod
public void setup()
throws IOException
{
server = new MockWebServer();
SSLContext sslContext = buildTestSslContext();
server.useHttps(sslContext.getSocketFactory(), false);
server.start();
}

@Override
@AfterMethod(alwaysRun = true)
public void teardown()
throws IOException
{
server.close();
}

@Test
public void testInsecureConnection()
{
server.enqueue(createMockResponse());
server.enqueue(createMockResponse());
executeQueries(createQueryRunner(createMockClientSession(), true),
ImmutableList.of("query with insecure mode;"));
try {
assertEquals(server.takeRequest(1, SECONDS).getPath(), "/v1/statement");
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}

private SSLContext buildTestSslContext()
throws IOException
{
try {
// Load self-signed certificate
char[] serverKeyStorePassword = "insecure-ssl-test".toCharArray();
KeyStore serverKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (InputStream in = getResource(getClass(), "/insecure-ssl-test.jks").openStream()) {
serverKeyStore.load(in, serverKeyStorePassword);
}
String kmfAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfAlgorithm);
kmf.init(serverKeyStore, serverKeyStorePassword);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(kmfAlgorithm);
trustManagerFactory.init(serverKeyStore);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
return sslContext;
}
catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException | KeyManagementException e) {
throw new IOException("failed to initialize SSL context", e);
}
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import java.net.Proxy;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
Expand Down Expand Up @@ -138,6 +139,41 @@ private static InetSocketAddress toUnresolvedAddress(HostAndPort address)
return InetSocketAddress.createUnresolved(address.getHost(), address.getPort());
}

public static void setupInsecureSsl(OkHttpClient.Builder clientBuilder)
{
try {
X509TrustManager trustAllCerts = new X509TrustManager()
{
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
{
throw new UnsupportedOperationException("checkClientTrusted should not be called");
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
{
// skip validation of server certificate
}

@Override
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[0];
}
};

SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[] {trustAllCerts}, new SecureRandom());

clientBuilder.sslSocketFactory(sslContext.getSocketFactory(), trustAllCerts);
clientBuilder.hostnameVerifier((hostname, session) -> true);
}
catch (GeneralSecurityException e) {
throw new ClientException("Error setting up SSL: " + e.getMessage(), e);
}
}

public static void setupSsl(
OkHttpClient.Builder clientBuilder,
Optional<String> keyStorePath,
Expand Down
46 changes: 35 additions & 11 deletions presto-docs/src/main/sphinx/clients/presto-cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,19 @@ Run the CLI with the ``--help`` option to see the online help.
./presto --help
NAME
presto - Presto interactive console

SYNOPSIS
presto [--access-token <access token>] [--catalog <catalog>]
[--client-info <client-info>]
[--client-request-timeout <client request timeout>]
[--client-tags <client tags>] [--debug] [--disable-compression]
[--execute <execute>] [--extra-credential <extra-credential>...]
[(-f <file> | --file <file>)] [(-h | --help)]
[--http-proxy <http-proxy>] [--ignore-errors]
[--keystore-password <keystore password>]
[--keystore-path <keystore path>]
[--disable-redirects] [--execute <execute>]
[--extra-credential <extra-credential>...] [(-f <file> | --file <file>)]
[(-h | --help)] [--http-proxy <http-proxy>] [--ignore-errors]
[--insecure] [--keystore-password <keystore password>]
[--keystore-path <keystore path>] [--keystore-type <keystore type>]
[--krb5-config-path <krb5 config path>]
[--krb5-credential-cache-path <krb5 credential cache path>]
[--krb5-disable-remote-service-hostname-canonicalization]
Expand All @@ -90,10 +93,12 @@ SYNOPSIS
[--krb5-remote-service-name <krb5 remote service name>]
[--log-levels-file <log levels file>] [--output-format <output-format>]
[--password] [--resource-estimate <resource-estimate>...]
[--schema <schema>] [--server <server>] [--session <session>...]
[--socks-proxy <socks-proxy>] [--source <source>]
[--truststore-password <truststore password>]
[--truststore-path <truststore path>] [--user <user>] [--version]
[--runtime-stats] [--schema <schema>] [--server <server>]
[--session <session>...] [--socks-proxy <socks-proxy>]
[--source <source>] [--truststore-password <truststore password>]
[--truststore-path <truststore path>]
[--truststore-type <truststore type>] [--user <user>]
[--validate-nexturi-source] [--version]

OPTIONS
--access-token <access token>
Expand All @@ -117,6 +122,9 @@ OPTIONS
--disable-compression
Disable compression of query results

--disable-redirects
Disable client following redirects from server

--execute <execute>
Execute specified statements and exit

Expand All @@ -137,12 +145,19 @@ OPTIONS
Continue processing in batch mode when an error occurs (default is
to exit immediately)

--insecure
Skip validation of HTTP server certificates (should only be used for
debugging)

--keystore-password <keystore password>
Keystore password

--keystore-path <keystore path>
Keystore path

--keystore-type <keystore type>
Keystore type

--krb5-config-path <krb5 config path>
Kerberos config file path (default: /etc/krb5.conf)

Expand All @@ -166,7 +181,7 @@ OPTIONS
Configure log levels for debugging using this file

--output-format <output-format>
Output format for batch mode [ALIGNED, VERTICAL, CSV, TSV,
Output format for batch mode [ALIGNED, VERTICAL, JSON, CSV, TSV,
CSV_HEADER, TSV_HEADER, NULL] (default: CSV)

--password
Expand All @@ -177,7 +192,8 @@ OPTIONS
key=value)

--runtime-stats
Enable runtime stats information. Flag must be used in conjunction with the --debug flag
Enable runtime stats information. Flag must be used in conjunction
with the --debug flag

--schema <schema>
Default schema
Expand All @@ -201,8 +217,16 @@ OPTIONS
--truststore-path <truststore path>
Truststore path

--truststore-type <truststore type>
Truststore type

--user <user>
Username

--validate-nexturi-source
Validate nextUri server host and port does not change during query
execution

--version
Display version information and exit

0 comments on commit 96c58c9

Please sign in to comment.