Skip to content

Commit

Permalink
Add insecure mode for CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
Lewuathe authored and electrum committed Sep 17, 2019
1 parent 16cdb9e commit 1c5b921
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 27 deletions.
3 changes: 3 additions & 0 deletions presto-cli/src/main/java/io/prestosql/cli/ClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ public class ClientOptions
@Option(name = "--truststore-password", title = "truststore password", description = "Truststore password")
public String truststorePassword;

@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 = "--access-token", title = "access token", description = "Access token")
public String accessToken;

Expand Down
1 change: 1 addition & 0 deletions presto-cli/src/main/java/io/prestosql/cli/Console.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ public boolean run()
Optional.ofNullable(clientOptions.keystorePassword),
Optional.ofNullable(clientOptions.truststorePath),
Optional.ofNullable(clientOptions.truststorePassword),
clientOptions.insecure,
Optional.ofNullable(clientOptions.accessToken),
Optional.ofNullable(clientOptions.user),
clientOptions.password ? Optional.of(getPassword()) : Optional.empty(),
Expand Down
9 changes: 8 additions & 1 deletion presto-cli/src/main/java/io/prestosql/cli/QueryRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import com.google.common.net.HostAndPort;
import io.prestosql.client.ClientSession;
import io.prestosql.client.OkHttpUtil;
import io.prestosql.client.SocketChannelSocketFactory;
import io.prestosql.client.StatementClient;
import okhttp3.OkHttpClient;
Expand Down Expand Up @@ -56,6 +57,7 @@ public QueryRunner(
Optional<String> keystorePassword,
Optional<String> truststorePath,
Optional<String> truststorePassword,
boolean insecureSsl,
Optional<String> accessToken,
Optional<String> user,
Optional<String> password,
Expand All @@ -70,7 +72,12 @@ public QueryRunner(
this.session = new AtomicReference<>(requireNonNull(session, "session is null"));
this.debug = debug;

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

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

Expand Down
104 changes: 104 additions & 0 deletions presto-cli/src/test/java/io/prestosql/cli/TestInsecureQueryRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* 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 io.prestosql.cli;

import okhttp3.mockwebserver.MockResponse;
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.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;

import static com.google.common.io.Resources.getResource;
import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
import static io.prestosql.cli.ClientOptions.OutputFormat.CSV;
import static io.prestosql.cli.TestQueryRunner.createClientSession;
import static io.prestosql.cli.TestQueryRunner.createQueryRunner;
import static io.prestosql.cli.TestQueryRunner.createResults;
import static io.prestosql.cli.TestQueryRunner.nullPrintStream;
import static org.testng.Assert.assertEquals;

@Test(singleThreaded = true)
public class TestInsecureQueryRunner
{
private MockWebServer server;

@BeforeMethod
public void setup()
throws Exception
{
server = new MockWebServer();
SSLContext sslContext = buildTestSslContext();
server.useHttps(sslContext.getSocketFactory(), false);
server.start();
}

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

@Test
public void testInsecureConnection()
{
server.enqueue(new MockResponse()
.addHeader(CONTENT_TYPE, "application/json")
.setBody(createResults(server)));
server.enqueue(new MockResponse()
.addHeader(CONTENT_TYPE, "application/json")
.setBody(createResults(server)));

QueryRunner queryRunner = createQueryRunner(createClientSession(server), true);
try (Query query = queryRunner.startQuery("query with insecure mode")) {
query.renderOutput(nullPrintStream(), nullPrintStream(), CSV, false, false);
}
try {
assertEquals(server.takeRequest().getPath(), "/v1/statement");
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}

private SSLContext buildTestSslContext()
throws Exception
{
// 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;
}
}
55 changes: 30 additions & 25 deletions presto-cli/src/test/java/io/prestosql/cli/TestQueryRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,31 +76,12 @@ public void testCookie()
.addHeader(SET_COOKIE, "a=apple"));
server.enqueue(new MockResponse()
.addHeader(CONTENT_TYPE, "application/json")
.setBody(createResults()));
.setBody(createResults(server)));
server.enqueue(new MockResponse()
.addHeader(CONTENT_TYPE, "application/json")
.setBody(createResults()));
.setBody(createResults(server)));

QueryRunner queryRunner = createQueryRunner(
new ClientSession(
server.url("/").uri(),
"user",
"source",
Optional.empty(),
ImmutableSet.of(),
"clientInfo",
"catalog",
"schema",
"path",
ZoneId.of("America/Los_Angeles"),
Locale.ENGLISH,
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
null,
new Duration(2, MINUTES)));
QueryRunner queryRunner = createQueryRunner(createClientSession(server), false);
try (Query query = queryRunner.startQuery("first query will introduce a cookie")) {
query.renderOutput(nullPrintStream(), nullPrintStream(), CSV, false, false);
}
Expand All @@ -118,7 +99,30 @@ public void testCookie()
}
}

private String createResults()
static ClientSession createClientSession(MockWebServer server)
{
return new ClientSession(
server.url("/").uri(),
"user",
"source",
Optional.empty(),
ImmutableSet.of(),
"clientInfo",
"catalog",
"schema",
"path",
ZoneId.of("America/Los_Angeles"),
Locale.ENGLISH,
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
null,
new Duration(2, MINUTES));
}

static String createResults(MockWebServer server)
{
QueryResults queryResults = new QueryResults(
"20160128_214710_00012_rk68b",
Expand All @@ -136,7 +140,7 @@ private String createResults()
return QUERY_RESULTS_CODEC.toJson(queryResults);
}

static QueryRunner createQueryRunner(ClientSession clientSession)
static QueryRunner createQueryRunner(ClientSession clientSession, boolean insecureSsl)
{
return new QueryRunner(
clientSession,
Expand All @@ -147,6 +151,7 @@ static QueryRunner createQueryRunner(ClientSession clientSession)
Optional.empty(),
Optional.empty(),
Optional.empty(),
insecureSsl,
Optional.empty(),
Optional.empty(),
Optional.empty(),
Expand All @@ -159,7 +164,7 @@ static QueryRunner createQueryRunner(ClientSession clientSession)
false);
}

private static PrintStream nullPrintStream()
static PrintStream nullPrintStream()
{
return new PrintStream(nullOutputStream());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class TestTableNameCompleter
public void testAutoCompleteWithoutSchema()
{
ClientSession session = new ClientOptions().toClientSession();
QueryRunner runner = createQueryRunner(session);
QueryRunner runner = createQueryRunner(session, false);

TableNameCompleter completer = new TableNameCompleter(runner);
assertEquals(completer.complete("SELECT is_infi", 14, ImmutableList.of()), 7);
Expand Down
Binary file not shown.
36 changes: 36 additions & 0 deletions presto-client/src/main/java/io/prestosql/client/OkHttpUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,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 @@ -125,6 +126,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

0 comments on commit 1c5b921

Please sign in to comment.