Skip to content

Commit

Permalink
support tls single authentication (#592)
Browse files Browse the repository at this point in the history
* support tls single authentication

* add example for ca cert
  • Loading branch information
Nicole00 committed Mar 27, 2024
1 parent 3ee144b commit 06945e3
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public class NebulaPoolConfig implements Serializable {
// Set to true to turn on ssl encrypted traffic
private boolean enableSsl = false;

// SSL param is required if ssl is turned on
// if enableSsl is true but SSL param is not config,
// then client will not verify the server certificate. Encrypted transmission only.
private SSLParam sslParam = null;

// Set if use http2 protocol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ public class CASignedSSLParam extends SSLParam {
private String crtFilePath;
private String keyFilePath;

public CASignedSSLParam() {
super(SignMode.CA_SIGNED);
}

public CASignedSSLParam(String caCrtFilePath, String crtFilePath, String keyFilePath) {
super(SignMode.CA_SIGNED);
this.caCrtFilePath = caCrtFilePath;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public abstract class SSLParam implements Serializable {

private static final long serialVersionUID = 7410233298826490747L;

private boolean skipVerifyServer = false;

public enum SignMode {
NONE,
SELF_SIGNED,
Expand All @@ -19,6 +21,14 @@ public enum SignMode {

private SignMode signMode;

public boolean isSkipVerifyServer() {
return skipVerifyServer;
}

public void setSkipVerifyServer(boolean skipVerifyServer) {
this.skipVerifyServer = skipVerifyServer;
}

public SSLParam(SignMode signMode) {
this.signMode = signMode;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ public SyncConnection create() throws IOErrorException, ClientServerIncompatible
while (retry-- > 0) {
try {
if (config.isEnableSsl()) {
if (config.getSslParam() == null) {
throw new IllegalArgumentException("SSL Param is required when enableSsl "
+ "is set to true");
}
conn.open(address, config.getTimeout(), config.getSslParam(),
config.isUseHttp2(), config.getCustomHeaders());
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public boolean ping(HostAddress addr) {
connection.close();
return pong;
} catch (IOErrorException e) {
LOGGER.warn(String.format("ping server %s failed", addr.toString()), e);
return false;
} catch (ClientServerIncompatibleException e) {
LOGGER.error("version verify failed, ", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ public void open(HostAddress address, int timeout, SSLParam sslParam, boolean is
this.useHttp2 = isUseHttp2;
this.headers = headers;
if (sslSocketFactory == null) {
if (sslParam.getSignMode() == SSLParam.SignMode.CA_SIGNED) {
if (sslParam == null) {
sslSocketFactory = SslUtil.getSSLSocketFactoryWithoutVerify();
} else if (sslParam.getSignMode() == SSLParam.SignMode.CA_SIGNED) {
sslSocketFactory =
SslUtil.getSSLSocketFactoryWithCA((CASignedSSLParam) sslParam);
} else {
Expand Down
88 changes: 88 additions & 0 deletions client/src/main/java/com/vesoft/nebula/util/SslUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,30 @@

import com.vesoft.nebula.client.graph.data.CASignedSSLParam;
import com.vesoft.nebula.client.graph.data.SelfSignedSSLParam;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
Expand All @@ -36,6 +49,20 @@ public class SslUtil {
private static TrustManager[] trustManagers;

public static SSLSocketFactory getSSLSocketFactoryWithCA(CASignedSSLParam param) {
// skip the verify for server certificate
if (param.isSkipVerifyServer()) {
return getSSLSocketFactoryWithoutVerify();
}

// if cert and key are null, consider the server certificate is CA,
// and verify if server certificate is CA.
if (param.getCaCrtFilePath() == null) {
return getSSLSocketFactoryVerifyCACert();
}


// verify server certificate using client config, the server certificate must be issued
// by client caCrt.
final String caCrtFile = param.getCaCrtFilePath();
final String crtFile = param.getCrtFilePath();
final String keyFile = param.getKeyFilePath();
Expand Down Expand Up @@ -220,4 +247,65 @@ public static SSLSocketFactory getSSLSocketFactoryWithoutCA(SelfSignedSSLParam p
public static TrustManager[] getTrustManagers() {
return trustManagers;
}


public static SSLSocketFactory getSSLSocketFactoryWithoutVerify() {
TrustManager[] trustManagers = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}

public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}

public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};

try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, null);
return sslContext.getSocketFactory();
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
return null;
}

/**
* check if the server's cert is issued by a CA
*/
public static SSLSocketFactory getSSLSocketFactoryVerifyCACert() {
try {
String trustStoreUrl = System.getProperty("javax.net.ssl.trustStore");
String trustStorePassword = System.getProperty("javax.net.ssl.trustStorePassword");
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());

if (trustStoreUrl == null || trustStorePassword == null) {
throw new RuntimeException(
"No truststore provided to verify the Server certificate,"
+ " please set javax.net.ssl.trustStore and "
+ "javax.net.ssl.trustStorePassword for the System.");
}
InputStream in = new FileInputStream(trustStoreUrl);
keystore.load(in, trustStorePassword.toCharArray());

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, trustStorePassword.toCharArray());

TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(keystore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return sslContext.getSocketFactory();
} catch (Exception e) {
LOGGER.error("get SSLSocketFactory error,", e);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* Copyright (c) 2024 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

package com.vesoft.nebula.examples;

import com.vesoft.nebula.client.graph.NebulaPoolConfig;
import com.vesoft.nebula.client.graph.data.CASignedSSLParam;
import com.vesoft.nebula.client.graph.data.HostAddress;
import com.vesoft.nebula.client.graph.data.ResultSet;
import com.vesoft.nebula.client.graph.exception.AuthFailedException;
import com.vesoft.nebula.client.graph.exception.ClientServerIncompatibleException;
import com.vesoft.nebula.client.graph.exception.IOErrorException;
import com.vesoft.nebula.client.graph.exception.NotValidConnectionException;
import com.vesoft.nebula.client.graph.net.NebulaPool;
import com.vesoft.nebula.client.graph.net.Session;
import java.net.UnknownHostException;
import java.util.Arrays;

/**
* if you trust server's self sign certificate, import the root certificate who issues
* server certificate into client system trust store using keytool:
* keytool -import -trustcacerts -alias root_ca -file Desktop/root.crt -keystore truststore.jks
* And load the local truststore.jks into system:
* System.setProperty("javax.net.ssl.trustStore", "/Users/nicole/truststore.jks");
* System.setProperty("javax.net.ssl.trustStorePassword", "123456");
*/

public class GraphSSLExample {
public static void main(String[] args) throws UnknownHostException, IOErrorException,
AuthFailedException, ClientServerIncompatibleException, NotValidConnectionException {
// if server use the certificate issued by CA , then please make sure your client trust
// store has been load in System.
String trustStorePath = System.getenv("JAVA_HOME") + "/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
// default password of JDK cacerts is changeit
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");


NebulaPoolConfig nebulaSslPoolConfig = new NebulaPoolConfig();
nebulaSslPoolConfig.setMaxConnSize(100);
// enable ssl
nebulaSslPoolConfig.setEnableSsl(true);
// config ssl is CA and config no certificate
nebulaSslPoolConfig.setSslParam(new CASignedSSLParam());

NebulaPool sslPool = new NebulaPool();
sslPool.init(Arrays.asList(new HostAddress(
"nebula-graph-nco13931ssfnnd8o6bk50.aws.dev.cloud.nebula-graph.io", 9669)),
nebulaSslPoolConfig);
String query = "YIELD 1";
Session sslSession = sslPool.getSession("dbaas-test@vesoft.com",
"H3prCPAh1POJEgxPkReEQQ", false);
ResultSet resp = sslSession.execute(query);

if (!resp.isSucceeded()) {
System.out.println(
String.format("Execute: `%s', failed: %s", query, resp.getErrorMessage()));
System.exit(1);
}
System.out.println(resp);
sslSession.release();
sslPool.close();
}
}

0 comments on commit 06945e3

Please sign in to comment.