diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 91f3ee1b1..d6270e2da 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -41,6 +41,33 @@ jobs: cp ../../client/src/test/resources/docker-compose.yaml . docker-compose up -d sleep 10 + docker-compose ps + popd + popd + + - name: Install nebula-graph with CA SSL + run: | + pushd tmp + mkdir ca + pushd ca + cp -r ../../client/src/test/resources/ssl . + cp ../../client/src/test/resources/docker-compose-casigned.yaml . + docker-compose -f docker-compose-casigned.yaml up -d + sleep 30 + docker-compose -f docker-compose-casigned.yaml ps + popd + popd + + - name: Install nebula-graph with Self SSL + run: | + pushd tmp + mkdir self + pushd self + cp -r ../../client/src/test/resources/ssl . + cp ../../client/src/test/resources/docker-compose-selfsigned.yaml . + docker-compose -f docker-compose-selfsigned.yaml up -d + sleep 30 + docker-compose -f docker-compose-selfsigned.yaml ps popd popd diff --git a/client/src/main/java/com/vesoft/nebula/client/graph/net/RoundRobinLoadBalancer.java b/client/src/main/java/com/vesoft/nebula/client/graph/net/RoundRobinLoadBalancer.java index 395eca3a0..9dd055e58 100644 --- a/client/src/main/java/com/vesoft/nebula/client/graph/net/RoundRobinLoadBalancer.java +++ b/client/src/main/java/com/vesoft/nebula/client/graph/net/RoundRobinLoadBalancer.java @@ -83,7 +83,6 @@ public boolean ping(HostAddress addr) { connection.close(); return true; } catch (IOErrorException | ClientServerIncompatibleException e) { - LOGGER.error("ping failed", e); return false; } } diff --git a/client/src/main/java/com/vesoft/nebula/client/meta/MetaClient.java b/client/src/main/java/com/vesoft/nebula/client/meta/MetaClient.java index 41c74e478..4fe02c70e 100644 --- a/client/src/main/java/com/vesoft/nebula/client/meta/MetaClient.java +++ b/client/src/main/java/com/vesoft/nebula/client/meta/MetaClient.java @@ -13,8 +13,12 @@ import com.google.common.base.Charsets; import com.vesoft.nebula.ErrorCode; import com.vesoft.nebula.HostAddr; +import com.vesoft.nebula.client.graph.data.CASignedSSLParam; import com.vesoft.nebula.client.graph.data.HostAddress; +import com.vesoft.nebula.client.graph.data.SSLParam; +import com.vesoft.nebula.client.graph.data.SelfSignedSSLParam; import com.vesoft.nebula.client.graph.exception.ClientServerIncompatibleException; +import com.vesoft.nebula.client.graph.exception.IOErrorException; import com.vesoft.nebula.client.meta.exception.ExecuteFailedException; import com.vesoft.nebula.meta.EdgeItem; import com.vesoft.nebula.meta.GetEdgeReq; @@ -43,12 +47,15 @@ import com.vesoft.nebula.meta.TagItem; import com.vesoft.nebula.meta.VerifyClientVersionReq; import com.vesoft.nebula.meta.VerifyClientVersionResp; +import com.vesoft.nebula.util.SslUtil; +import java.io.IOException; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; +import javax.net.ssl.SSLSocketFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,6 +70,9 @@ public class MetaClient extends AbstractMetaClient { private static final int DEFAULT_EXECUTION_RETRY_SIZE = 3; private static final int RETRY_TIMES = 1; + private boolean enableSSL = false; + private SSLParam sslParam = null; + private MetaService.Client client; private final List addresses; @@ -88,6 +98,17 @@ public MetaClient(List addresses, int timeout, int connectionRetry, this.addresses = addresses; } + public MetaClient(List addresses, int timeout, int connectionRetry, + int executionRetry, boolean enableSSL, SSLParam sslParam) { + super(addresses, timeout, connectionRetry, executionRetry); + this.addresses = addresses; + this.enableSSL = enableSSL; + this.sslParam = sslParam; + if (enableSSL && sslParam == null) { + throw new IllegalArgumentException("SSL is enabled, but SSLParam is null."); + } + } + public void connect() throws TException, ClientServerIncompatibleException { doConnect(); @@ -106,8 +127,25 @@ private void doConnect() private void getClient(String host, int port) throws TTransportException, ClientServerIncompatibleException { - transport = new TSocket(host, port, timeout, timeout); - transport.open(); + if (enableSSL) { + SSLSocketFactory sslSocketFactory; + if (sslParam.getSignMode() == SSLParam.SignMode.CA_SIGNED) { + sslSocketFactory = SslUtil.getSSLSocketFactoryWithCA((CASignedSSLParam) sslParam); + } else { + sslSocketFactory = + SslUtil.getSSLSocketFactoryWithoutCA((SelfSignedSSLParam) sslParam); + } + try { + transport = new TSocket(sslSocketFactory.createSocket(host, port), timeout, + timeout); + } catch (IOException e) { + throw new TTransportException(IOErrorException.E_UNKNOWN, e); + } + } else { + transport = new TSocket(host, port, timeout, timeout); + transport.open(); + } + protocol = new TCompactProtocol(transport); client = new MetaService.Client(protocol); diff --git a/client/src/main/java/com/vesoft/nebula/client/meta/MetaManager.java b/client/src/main/java/com/vesoft/nebula/client/meta/MetaManager.java index e26d389b2..5c6bbf185 100644 --- a/client/src/main/java/com/vesoft/nebula/client/meta/MetaManager.java +++ b/client/src/main/java/com/vesoft/nebula/client/meta/MetaManager.java @@ -10,6 +10,7 @@ import com.google.common.collect.Maps; import com.vesoft.nebula.HostAddr; import com.vesoft.nebula.client.graph.data.HostAddress; +import com.vesoft.nebula.client.graph.data.SSLParam; import com.vesoft.nebula.client.graph.exception.ClientServerIncompatibleException; import com.vesoft.nebula.client.meta.exception.ExecuteFailedException; import com.vesoft.nebula.meta.EdgeItem; @@ -47,6 +48,10 @@ private class SpaceInfo { private MetaClient metaClient; private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + private static final int DEFAULT_TIMEOUT_MS = 1000; + private static final int DEFAULT_CONNECTION_RETRY_SIZE = 3; + private static final int DEFAULT_EXECUTION_RETRY_SIZE = 3; + /** * init the meta info cache */ @@ -57,6 +62,18 @@ public MetaManager(List address) fillMetaInfo(); } + /** + * init the meta info cache with more config + */ + public MetaManager(List address, int timeout, int connectionRetry, + int executionRetry, boolean enableSSL, SSLParam sslParam) + throws TException, ClientServerIncompatibleException { + metaClient = new MetaClient(address, timeout, connectionRetry, executionRetry, enableSSL, + sslParam); + metaClient.connect(); + fillMetaInfo(); + } + /** * close meta client */ diff --git a/client/src/main/java/com/vesoft/nebula/client/storage/GraphStorageConnection.java b/client/src/main/java/com/vesoft/nebula/client/storage/GraphStorageConnection.java index c1b54fc1f..8a614df79 100644 --- a/client/src/main/java/com/vesoft/nebula/client/storage/GraphStorageConnection.java +++ b/client/src/main/java/com/vesoft/nebula/client/storage/GraphStorageConnection.java @@ -11,14 +11,22 @@ import com.facebook.thrift.protocol.TProtocol; import com.facebook.thrift.transport.TSocket; import com.facebook.thrift.transport.TTransport; +import com.facebook.thrift.transport.TTransportException; +import com.vesoft.nebula.client.graph.data.CASignedSSLParam; import com.vesoft.nebula.client.graph.data.HostAddress; +import com.vesoft.nebula.client.graph.data.SSLParam; +import com.vesoft.nebula.client.graph.data.SelfSignedSSLParam; +import com.vesoft.nebula.client.graph.exception.IOErrorException; import com.vesoft.nebula.storage.GraphStorageService; import com.vesoft.nebula.storage.ScanEdgeRequest; import com.vesoft.nebula.storage.ScanEdgeResponse; import com.vesoft.nebula.storage.ScanVertexRequest; import com.vesoft.nebula.storage.ScanVertexResponse; +import com.vesoft.nebula.util.SslUtil; +import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; +import javax.net.ssl.SSLSocketFactory; public class GraphStorageConnection { protected TTransport transport = null; @@ -29,15 +37,37 @@ public class GraphStorageConnection { protected GraphStorageConnection() { } - protected GraphStorageConnection open(HostAddress address, int timeout) throws Exception { + protected GraphStorageConnection open(HostAddress address, int timeout, boolean enableSSL, + SSLParam sslParam) throws Exception { this.address = address; int newTimeout = timeout <= 0 ? Integer.MAX_VALUE : timeout; - this.transport = new TSocket( - InetAddress.getByName(address.getHost()).getHostAddress(), - address.getPort(), - newTimeout, - newTimeout); - this.transport.open(); + if (enableSSL) { + SSLSocketFactory sslSocketFactory; + if (sslParam.getSignMode() == SSLParam.SignMode.CA_SIGNED) { + sslSocketFactory = SslUtil.getSSLSocketFactoryWithCA((CASignedSSLParam) sslParam); + } else { + sslSocketFactory = + SslUtil.getSSLSocketFactoryWithoutCA((SelfSignedSSLParam) sslParam); + } + try { + transport = + new TSocket( + sslSocketFactory.createSocket( + InetAddress.getByName(address.getHost()).getHostAddress(), + address.getPort()), + newTimeout, + newTimeout); + } catch (IOException e) { + throw new TTransportException(IOErrorException.E_UNKNOWN, e); + } + } else { + this.transport = new TSocket( + InetAddress.getByName(address.getHost()).getHostAddress(), + address.getPort(), + newTimeout, + newTimeout); + this.transport.open(); + } this.protocol = new TCompactProtocol(transport); client = new GraphStorageService.Client(protocol); return this; diff --git a/client/src/main/java/com/vesoft/nebula/client/storage/StorageClient.java b/client/src/main/java/com/vesoft/nebula/client/storage/StorageClient.java index d7c9b27f8..9de258c10 100644 --- a/client/src/main/java/com/vesoft/nebula/client/storage/StorageClient.java +++ b/client/src/main/java/com/vesoft/nebula/client/storage/StorageClient.java @@ -8,6 +8,7 @@ import com.vesoft.nebula.HostAddr; import com.vesoft.nebula.client.graph.data.HostAddress; +import com.vesoft.nebula.client.graph.data.SSLParam; import com.vesoft.nebula.client.meta.MetaManager; import com.vesoft.nebula.client.storage.scan.PartScanInfo; import com.vesoft.nebula.client.storage.scan.ScanEdgeResultIterator; @@ -34,6 +35,11 @@ public class StorageClient { private MetaManager metaManager; private final List addresses; private int timeout = 10000; // ms + private int connectionRetry = 3; + private int executionRetry = 1; + + private boolean enableSSL = false; + private SSLParam sslParam = null; /** * Get a Nebula Storage client that executes the scan query to get NebulaGraph's data with @@ -70,16 +76,35 @@ public StorageClient(List addresses, int timeout) { this.timeout = timeout; } + /** + * Get a Nebula Storage client that executes the scan query to get NebulaGraph's data with + * multi servers' hosts, timeout and ssl config. + */ + public StorageClient(List addresses, int timeout, int connectionRetry, + int executionRetry, boolean enableSSL, SSLParam sslParam) { + this(addresses, timeout); + this.connectionRetry = connectionRetry; + this.executionRetry = executionRetry; + this.enableSSL = enableSSL; + this.sslParam = sslParam; + if (enableSSL && sslParam == null) { + throw new IllegalArgumentException("SSL is enabled, but SSLParam is nul."); + } + } + /** * Connect to Nebula Storage server. * * @return true if connect successfully. */ public boolean connect() throws Exception { - connection.open(addresses.get(0), timeout); + connection.open(addresses.get(0), timeout, enableSSL, sslParam); StoragePoolConfig config = new StoragePoolConfig(); + config.setEnableSSL(enableSSL); + config.setSslParam(sslParam); pool = new StorageConnPool(config); - metaManager = new MetaManager(addresses); + metaManager = new MetaManager(addresses, timeout, connectionRetry, executionRetry, + enableSSL, sslParam); return true; } diff --git a/client/src/main/java/com/vesoft/nebula/client/storage/StorageConnPoolFactory.java b/client/src/main/java/com/vesoft/nebula/client/storage/StorageConnPoolFactory.java index 2521d408b..88472d9fe 100644 --- a/client/src/main/java/com/vesoft/nebula/client/storage/StorageConnPoolFactory.java +++ b/client/src/main/java/com/vesoft/nebula/client/storage/StorageConnPoolFactory.java @@ -56,7 +56,11 @@ public boolean validateObject(HostAddress hostAndPort, public void activateObject(HostAddress address, PooledObject pooledObject) throws Exception { - pooledObject.getObject().open(address, config.getTimeout()); + pooledObject.getObject().open( + address, + config.getTimeout(), + config.isEnableSSL(), + config.getSslParam()); } @Override diff --git a/client/src/main/java/com/vesoft/nebula/client/storage/StoragePoolConfig.java b/client/src/main/java/com/vesoft/nebula/client/storage/StoragePoolConfig.java index 347fda67b..82c879ea6 100644 --- a/client/src/main/java/com/vesoft/nebula/client/storage/StoragePoolConfig.java +++ b/client/src/main/java/com/vesoft/nebula/client/storage/StoragePoolConfig.java @@ -7,6 +7,8 @@ package com.vesoft.nebula.client.storage; +import com.vesoft.nebula.client.graph.data.SSLParam; + public class StoragePoolConfig { // The min connections in pool for all addresses private int minConnsSize = 0; @@ -28,6 +30,10 @@ public class StoragePoolConfig { // the max total connection in pool for each key private int maxTotalPerKey = 10; + private boolean enableSSL = false; + + private SSLParam sslParam = null; + public int getMinConnsSize() { return minConnsSize; } @@ -75,4 +81,20 @@ public int getMaxTotalPerKey() { public void setMaxTotalPerKey(int maxTotalPerKey) { this.maxTotalPerKey = maxTotalPerKey; } + + public boolean isEnableSSL() { + return enableSSL; + } + + public void setEnableSSL(boolean enableSSL) { + this.enableSSL = enableSSL; + } + + public SSLParam getSslParam() { + return sslParam; + } + + public void setSslParam(SSLParam sslParam) { + this.sslParam = sslParam; + } } diff --git a/client/src/test/java/com/vesoft/nebula/client/graph/data/TestDataFromServer.java b/client/src/test/java/com/vesoft/nebula/client/graph/data/TestDataFromServer.java index 0718e985c..5140f7e0c 100644 --- a/client/src/test/java/com/vesoft/nebula/client/graph/data/TestDataFromServer.java +++ b/client/src/test/java/com/vesoft/nebula/client/graph/data/TestDataFromServer.java @@ -555,9 +555,6 @@ public void testSelfSignedSsl() { Session sslSession = null; NebulaPool sslPool = new NebulaPool(); try { - Runtime runtime = Runtime.getRuntime(); - runtime.exec("docker-compose -f src/test/resources/docker-compose" - + "-selfsigned.yaml up -d"); NebulaPoolConfig nebulaSslPoolConfig = new NebulaPoolConfig(); nebulaSslPoolConfig.setMaxConnSize(100); @@ -566,8 +563,7 @@ public void testSelfSignedSsl() { "src/test/resources/ssl/selfsigned.pem", "src/test/resources/ssl/selfsigned.key", "vesoft")); - TimeUnit.SECONDS.sleep(45); - Assert.assertTrue(sslPool.init(Arrays.asList(new HostAddress("127.0.0.1", 8669)), + Assert.assertTrue(sslPool.init(Arrays.asList(new HostAddress("127.0.0.1", 7669)), nebulaSslPoolConfig)); sslSession = sslPool.getSession("root", "nebula", true); @@ -577,9 +573,6 @@ public void testSelfSignedSsl() { .getJSONObject(0).getJSONArray("row").toJSONString(); String exp = "[1]"; Assert.assertEquals(rowData, exp); - - runtime.exec("docker-compose -f src/test/resources/docker-compose" - + "-selfsigned.yaml down").waitFor(60, TimeUnit.SECONDS); } catch (Exception e) { e.printStackTrace(); assert false; @@ -596,10 +589,6 @@ public void testCASignedSsl() { Session sslSession = null; NebulaPool sslPool = new NebulaPool(); try { - Runtime runtime = Runtime.getRuntime(); - runtime.exec("docker-compose -f src/test/resources/docker-compose" - + "-casigned.yaml up -d"); - NebulaPoolConfig nebulaSslPoolConfig = new NebulaPoolConfig(); nebulaSslPoolConfig.setMaxConnSize(100); nebulaSslPoolConfig.setEnableSsl(true); @@ -607,7 +596,6 @@ public void testCASignedSsl() { "src/test/resources/ssl/casigned.pem", "src/test/resources/ssl/casigned.crt", "src/test/resources/ssl/casigned.key")); - TimeUnit.SECONDS.sleep(45); Assert.assertTrue(sslPool.init(Arrays.asList(new HostAddress("127.0.0.1", 8669)), nebulaSslPoolConfig)); sslSession = sslPool.getSession("root", "nebula", true); @@ -619,8 +607,6 @@ public void testCASignedSsl() { String exp = "[1]"; Assert.assertEquals(rowData, exp); - runtime.exec("docker-compose -f src/test/resources/docker-compose" - + "-casigned.yaml down").waitFor(60, TimeUnit.SECONDS); } catch (Exception e) { e.printStackTrace(); assert false; diff --git a/client/src/test/java/com/vesoft/nebula/client/meta/MockNebulaGraph.java b/client/src/test/java/com/vesoft/nebula/client/meta/MockNebulaGraph.java index 2643824e4..1e8585b6f 100644 --- a/client/src/test/java/com/vesoft/nebula/client/meta/MockNebulaGraph.java +++ b/client/src/test/java/com/vesoft/nebula/client/meta/MockNebulaGraph.java @@ -7,8 +7,10 @@ package com.vesoft.nebula.client.meta; 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.data.SelfSignedSSLParam; import com.vesoft.nebula.client.graph.exception.AuthFailedException; import com.vesoft.nebula.client.graph.exception.ClientServerIncompatibleException; import com.vesoft.nebula.client.graph.exception.IOErrorException; @@ -61,6 +63,24 @@ public static String createSpace() { return exec; } + public static String createSpaceCA() { + String exec = "CREATE SPACE IF NOT EXISTS testMetaCA(partition_num=10, " + + "vid_type=fixed_string(8));" + + "USE testMetaCA;" + + "CREATE TAG IF NOT EXISTS person(name string, age int);" + + "CREATE EDGE IF NOT EXISTS friend(likeness double);"; + return exec; + } + + public static String createSpaceSelf() { + String exec = "CREATE SPACE IF NOT EXISTS testMetaSelf(partition_num=10, " + + "vid_type=fixed_string(8));" + + "USE testMetaSelf;" + + "CREATE TAG IF NOT EXISTS person(name string, age int);" + + "CREATE EDGE IF NOT EXISTS friend(likeness double);"; + return exec; + } + public static void createMultiVersionTagAndEdge() { NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig(); nebulaPoolConfig.setMaxConnSize(100); @@ -99,4 +119,68 @@ public static void createMultiVersionTagAndEdge() { pool.close(); } } + + public static void createSpaceWithCASSL() { + NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig(); + nebulaPoolConfig.setMaxConnSize(100); + nebulaPoolConfig.setEnableSsl(true); + nebulaPoolConfig.setSslParam(new CASignedSSLParam( + "src/test/resources/ssl/casigned.pem", + "src/test/resources/ssl/casigned.crt", + "src/test/resources/ssl/casigned.key")); + List addresses = Arrays.asList(new HostAddress("127.0.0.1", 8669)); + NebulaPool pool = new NebulaPool(); + Session session = null; + try { + pool.init(addresses, nebulaPoolConfig); + session = pool.getSession("root", "nebula", true); + + ResultSet resp = session.execute(createSpaceCA()); + if (!resp.isSucceeded()) { + LOGGER.error("create space failed, {}", resp.getErrorMessage()); + assert (false); + } + Thread.sleep(5000); + + } catch (Exception e) { + LOGGER.error("create space with CA ssl error, ", e); + assert (false); + } finally { + if (session != null) { + session.release(); + } + pool.close(); + } + } + + public static void createSpaceWithSelfSSL() { + NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig(); + nebulaPoolConfig.setMaxConnSize(100); + nebulaPoolConfig.setEnableSsl(true); + nebulaPoolConfig.setSslParam(new SelfSignedSSLParam( + "src/test/resources/ssl/selfsigned.pem", + "src/test/resources/ssl/selfsigned.key", + "vesoft")); + List addresses = Arrays.asList(new HostAddress("127.0.0.1", 7669)); + NebulaPool pool = new NebulaPool(); + Session session = null; + try { + pool.init(addresses, nebulaPoolConfig); + session = pool.getSession("root", "nebula", true); + ResultSet resp = session.execute(createSpaceSelf()); + if (!resp.isSucceeded()) { + LOGGER.error("create space failed, {}", resp.getErrorMessage()); + assert (false); + } + Thread.sleep(5000); + } catch (Exception e) { + LOGGER.error("create space with Self ssl error, ", e); + assert (false); + } finally { + if (session != null) { + session.release(); + } + pool.close(); + } + } } diff --git a/client/src/test/java/com/vesoft/nebula/client/meta/TestMetaClient.java b/client/src/test/java/com/vesoft/nebula/client/meta/TestMetaClient.java index 6a0a53660..a450883f4 100644 --- a/client/src/test/java/com/vesoft/nebula/client/meta/TestMetaClient.java +++ b/client/src/test/java/com/vesoft/nebula/client/meta/TestMetaClient.java @@ -7,12 +7,18 @@ package com.vesoft.nebula.client.meta; import com.facebook.thrift.TException; +import com.vesoft.nebula.client.graph.data.CASignedSSLParam; +import com.vesoft.nebula.client.graph.data.HostAddress; +import com.vesoft.nebula.client.graph.data.SSLParam; +import com.vesoft.nebula.client.graph.data.SelfSignedSSLParam; import com.vesoft.nebula.client.graph.exception.ClientServerIncompatibleException; import com.vesoft.nebula.client.meta.exception.ExecuteFailedException; import com.vesoft.nebula.client.util.ProcessUtil; import com.vesoft.nebula.meta.EdgeItem; import com.vesoft.nebula.meta.IdName; import com.vesoft.nebula.meta.TagItem; +import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; import junit.framework.TestCase; @@ -134,4 +140,61 @@ public void testListOnlineHosts() { assert (false); } } + + public void testCASignedSSLMetaClient() { + MetaClient metaClient = null; + try { + + // mock data with CA ssl + MockNebulaGraph.createSpaceWithCASSL(); + + SSLParam sslParam = new CASignedSSLParam( + "src/test/resources/ssl/casigned.pem", + "src/test/resources/ssl/casigned.crt", + "src/test/resources/ssl/casigned.key"); + + metaClient = new MetaClient(Arrays.asList(new HostAddress(address, 8559)), + 3000, 1, 1, true, sslParam); + metaClient.connect(); + + List tags = metaClient.getTags("testMetaCA"); + Assert.assertTrue(tags.size() >= 1); + assert (metaClient.getTag("testMetaCA", "person") != null); + } catch (Exception e) { + LOGGER.error("test CA signed ssl meta client failed, ", e); + assert (false); + } finally { + if (metaClient != null) { + metaClient.close(); + } + } + } + + public void testSelfSignedSSLMetaClient() { + MetaClient metaClient = null; + try { + + // mock data with Self ssl + MockNebulaGraph.createSpaceWithSelfSSL(); + + SSLParam sslParam = new SelfSignedSSLParam( + "src/test/resources/ssl/selfsigned.pem", + "src/test/resources/ssl/selfsigned.key", + "vesoft"); + metaClient = new MetaClient(Arrays.asList(new HostAddress(address, 7559)), + 3000, 1, 1, true, sslParam); + metaClient.connect(); + + List tags = metaClient.getTags("testMetaSelf"); + Assert.assertTrue(tags.size() >= 1); + assert (metaClient.getTag("testMetaSelf", "person") != null); + } catch (Exception e) { + LOGGER.error("test Self signed ssl meta client failed, ", e); + assert (false); + } finally { + if (metaClient != null) { + metaClient.close(); + } + } + } } diff --git a/client/src/test/java/com/vesoft/nebula/client/meta/TestMetaManager.java b/client/src/test/java/com/vesoft/nebula/client/meta/TestMetaManager.java index 9782a3924..992f38c75 100644 --- a/client/src/test/java/com/vesoft/nebula/client/meta/TestMetaManager.java +++ b/client/src/test/java/com/vesoft/nebula/client/meta/TestMetaManager.java @@ -7,14 +7,21 @@ package com.vesoft.nebula.client.meta; import com.vesoft.nebula.HostAddr; +import com.vesoft.nebula.client.graph.data.CASignedSSLParam; import com.vesoft.nebula.client.graph.data.HostAddress; +import com.vesoft.nebula.client.graph.data.SSLParam; +import com.vesoft.nebula.client.graph.data.SelfSignedSSLParam; import com.vesoft.nebula.client.graph.exception.ClientServerIncompatibleException; +import com.vesoft.nebula.client.util.ProcessUtil; import com.vesoft.nebula.meta.EdgeItem; import com.vesoft.nebula.meta.SpaceItem; import com.vesoft.nebula.meta.TagItem; +import java.io.IOException; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; import junit.framework.TestCase; import org.junit.Assert; @@ -111,4 +118,80 @@ public void testMultiVersionSchema() throws ClientServerIncompatibleException { assert (edgeItem.getVersion() == 1); assert (edgeItem.schema.getColumns().size() == 1); } + + + public void testCASignedSSLMetaManager() { + MetaManager metaManager = null; + try { + + // mock data with CA ssl + MockNebulaGraph.createSpaceWithCASSL(); + + SSLParam sslParam = new CASignedSSLParam( + "src/test/resources/ssl/casigned.pem", + "src/test/resources/ssl/casigned.crt", + "src/test/resources/ssl/casigned.key"); + + metaManager = new MetaManager(Arrays.asList(new HostAddress("127.0.0.1", + 8559)), 3000, 1, 1, true, sslParam); + + + assert (metaManager.getSpaceId("testMetaCA") > 0); + SpaceItem spaceItem = metaManager.getSpace("testMetaCA"); + assert Objects.equals("testMetaCA", new String(spaceItem.properties.getSpace_name())); + Assert.assertEquals(8, spaceItem.properties.getVid_type().getType_length()); + Assert.assertEquals(10, spaceItem.properties.getPartition_num()); + + // test get not existed space + try { + metaManager.getSpace("not_existed"); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertTrue("We expected here", true); + } + } catch (Exception e) { + Assert.fail(); + } finally { + if (metaManager != null) { + metaManager.close(); + } + } + } + + public void testSelfSignedSSLMetaClient() { + MetaManager metaManager = null; + try { + + // mock data with Self ssl + MockNebulaGraph.createSpaceWithSelfSSL(); + + SSLParam sslParam = new SelfSignedSSLParam( + "src/test/resources/ssl/selfsigned.pem", + "src/test/resources/ssl/selfsigned.key", + "vesoft"); + metaManager = new MetaManager(Arrays.asList(new HostAddress("127.0.0.1", 7559)), + 3000, 1, 1, true, sslParam); + + assert (metaManager.getSpaceId("testMetaSelf") > 0); + SpaceItem spaceItem = metaManager.getSpace("testMetaSelf"); + assert Objects.equals("testMetaSelf", new String(spaceItem.properties.getSpace_name())); + Assert.assertEquals(8, spaceItem.properties.getVid_type().getType_length()); + Assert.assertEquals(10, spaceItem.properties.getPartition_num()); + + // test get not existed space + try { + metaManager.getSpace("not_existed"); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertTrue("We expected here", true); + } + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(); + } finally { + if (metaManager != null) { + metaManager.close(); + } + } + } } diff --git a/client/src/test/java/com/vesoft/nebula/client/storage/MockStorageData.java b/client/src/test/java/com/vesoft/nebula/client/storage/MockStorageData.java index 8a376b506..f8bdfea92 100644 --- a/client/src/test/java/com/vesoft/nebula/client/storage/MockStorageData.java +++ b/client/src/test/java/com/vesoft/nebula/client/storage/MockStorageData.java @@ -7,8 +7,10 @@ package com.vesoft.nebula.client.storage; 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.data.SelfSignedSSLParam; import com.vesoft.nebula.client.graph.exception.AuthFailedException; import com.vesoft.nebula.client.graph.exception.ClientServerIncompatibleException; import com.vesoft.nebula.client.graph.exception.IOErrorException; @@ -66,6 +68,24 @@ public static String createSpace() { return exec; } + public static String createSpaceCa() { + String exec = "CREATE SPACE IF NOT EXISTS testStorageCA(partition_num=10," + + "vid_type=fixed_string(8));" + + "USE testStorageCA;" + + "CREATE TAG IF NOT EXISTS person(name string, age int);" + + "CREATE EDGE IF NOT EXISTS friend(likeness double);"; + return exec; + } + + public static String createSpaceSelf() { + String exec = "CREATE SPACE IF NOT EXISTS testStorageSelf(partition_num=10," + + "vid_type=fixed_string(8));" + + "USE testStorageSelf;" + + "CREATE TAG IF NOT EXISTS person(name string, age int);" + + "CREATE EDGE IF NOT EXISTS friend(likeness double);"; + return exec; + } + public static String insertData() { String exec = "INSERT VERTEX person(name, age) VALUES " + "\"1\":(\"Tom\", 18), " @@ -81,4 +101,85 @@ public static String insertData() { + "\"5\" -> \"1\":(5.9);"; return exec; } + + // mock data for CA ssl nebula service + public static void mockCASslData() { + NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig(); + nebulaPoolConfig.setMaxConnSize(100); + nebulaPoolConfig.setEnableSsl(true); + nebulaPoolConfig.setSslParam(new CASignedSSLParam( + "src/test/resources/ssl/casigned.pem", + "src/test/resources/ssl/casigned.crt", + "src/test/resources/ssl/casigned.key")); + List addresses = Arrays.asList(new HostAddress("127.0.0.1", 8669)); + NebulaPool pool = new NebulaPool(); + Session session = null; + try { + pool.init(addresses, nebulaPoolConfig); + session = pool.getSession("root", "nebula", true); + + ResultSet resp = session.execute(createSpaceCa()); + try { + Thread.sleep(6000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + ResultSet insertVertexResult = session.execute(insertData()); + if (!resp.isSucceeded() || !insertVertexResult.isSucceeded()) { + LOGGER.error("create space failed, {}", resp.getErrorMessage()); + LOGGER.error("insert vertex data failed, {}", insertVertexResult.getErrorMessage()); + assert (false); + } + } catch (UnknownHostException | NotValidConnectionException + | IOErrorException | AuthFailedException | ClientServerIncompatibleException e) { + e.printStackTrace(); + } finally { + if (session != null) { + session.release(); + } + pool.close(); + } + } + + // mock data for Self ssl nebula service + public static void mockSelfSslData() { + NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig(); + nebulaPoolConfig.setMaxConnSize(100); + nebulaPoolConfig.setEnableSsl(true); + nebulaPoolConfig.setSslParam(new SelfSignedSSLParam( + "src/test/resources/ssl/selfsigned.pem", + "src/test/resources/ssl/selfsigned.key", + "vesoft")); + List addresses = Arrays.asList(new HostAddress("127.0.0.1", 8669)); + NebulaPool pool = new NebulaPool(); + Session session = null; + try { + pool.init(addresses, nebulaPoolConfig); + session = pool.getSession("root", "nebula", true); + + ResultSet resp = session.execute(createSpaceSelf()); + + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + ResultSet insertVertexResult = session.execute(insertData()); + if (!resp.isSucceeded() || !insertVertexResult.isSucceeded()) { + LOGGER.error(resp.getErrorMessage()); + LOGGER.error(insertVertexResult.getErrorMessage()); + assert (false); + } + } catch (UnknownHostException | NotValidConnectionException + | IOErrorException | AuthFailedException | ClientServerIncompatibleException e) { + e.printStackTrace(); + } finally { + if (session != null) { + session.release(); + } + pool.close(); + } + } } diff --git a/client/src/test/java/com/vesoft/nebula/client/storage/StorageClientTest.java b/client/src/test/java/com/vesoft/nebula/client/storage/StorageClientTest.java index 0b2722ee8..22f0e16a4 100644 --- a/client/src/test/java/com/vesoft/nebula/client/storage/StorageClientTest.java +++ b/client/src/test/java/com/vesoft/nebula/client/storage/StorageClientTest.java @@ -6,7 +6,10 @@ package com.vesoft.nebula.client.storage; +import com.vesoft.nebula.client.graph.data.CASignedSSLParam; import com.vesoft.nebula.client.graph.data.HostAddress; +import com.vesoft.nebula.client.graph.data.SSLParam; +import com.vesoft.nebula.client.graph.data.SelfSignedSSLParam; import com.vesoft.nebula.client.storage.data.EdgeRow; import com.vesoft.nebula.client.storage.data.EdgeTableRow; import com.vesoft.nebula.client.storage.data.VertexRow; @@ -15,9 +18,12 @@ import com.vesoft.nebula.client.storage.scan.ScanEdgeResultIterator; import com.vesoft.nebula.client.storage.scan.ScanVertexResult; import com.vesoft.nebula.client.storage.scan.ScanVertexResultIterator; +import com.vesoft.nebula.client.util.ProcessUtil; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.List; +import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -360,4 +366,161 @@ public void testScanEdgeWithAllCols() { assert (result.isAllSuccess()); } } + + @Test + public void testCASignedSSL() { + // start nebula service with ssl enable + List address = null; + StorageClient sslClient = null; + try { + address = Arrays.asList(new HostAddress(ip, 8559)); + + // mock graph data + MockStorageData.mockCASslData(); + + SSLParam sslParam = new CASignedSSLParam( + "src/test/resources/ssl/casigned.pem", + "src/test/resources/ssl/casigned.crt", + "src/test/resources/ssl/casigned.key"); + sslClient = new StorageClient(address, 1000, 1, 1, true, sslParam); + sslClient.connect(); + + ScanVertexResultIterator resultIterator = sslClient.scanVertex( + "testStorageCA", + "person"); + while (resultIterator.hasNext()) { + ScanVertexResult result = null; + try { + result = resultIterator.next(); + } catch (Exception e) { + e.printStackTrace(); + assert (false); + } + if (result.isEmpty()) { + continue; + } + Assert.assertEquals(1, result.getPropNames().size()); + assert (result.getPropNames().get(0).equals("_vid")); + assert (result.isAllSuccess()); + + List rows = result.getVertices(); + for (VertexRow row : rows) { + try { + assert (Arrays.asList("1", "2", "3", "4", "5") + .contains(row.getVid().asString())); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + assert (false); + } + assert (row.getProps().size() == 0); + } + + List tableRows = result.getVertexTableRows(); + for (VertexTableRow tableRow : tableRows) { + try { + assert (Arrays.asList("1", "2", "3", "4", "5") + .contains(tableRow.getVid().asString())); + assert (Arrays.asList("1", "2", "3", "4", "5") + .contains(tableRow.getString(0))); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + assert (false); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + assert (false); + } finally { + if (sslClient != null) { + try { + sslClient.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + + @Test + public void testSelfSignedSSL() { + // start nebula service with ssl enable + List address = null; + StorageClient sslClient = null; + Runtime runtime = Runtime.getRuntime(); + try { + + address = Arrays.asList(new HostAddress(ip, 8559)); + + // mock graph data + MockStorageData.mockSelfSslData(); + + SSLParam sslParam = new SelfSignedSSLParam( + "src/test/resources/ssl/selfsigned.pem", + "src/test/resources/ssl/selfsigned.key", + "vesoft"); + sslClient = new StorageClient(address, 1000, 1, 1, true, sslParam); + sslClient.connect(); + + ScanVertexResultIterator resultIterator = sslClient.scanVertex( + "testStorageSelf", + "person"); + assertIterator(resultIterator); + } catch (Exception e) { + e.printStackTrace(); + assert (false); + } finally { + if (sslClient != null) { + try { + sslClient.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + private void assertIterator(ScanVertexResultIterator resultIterator) { + while (resultIterator.hasNext()) { + ScanVertexResult result = null; + try { + result = resultIterator.next(); + } catch (Exception e) { + e.printStackTrace(); + assert (false); + } + if (result.isEmpty()) { + continue; + } + Assert.assertEquals(1, result.getPropNames().size()); + assert (result.getPropNames().get(0).equals("_vid")); + assert (result.isAllSuccess()); + + List rows = result.getVertices(); + for (VertexRow row : rows) { + try { + assert (Arrays.asList("1", "2", "3", "4", "5") + .contains(row.getVid().asString())); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + assert (false); + } + assert (row.getProps().size() == 0); + } + + List tableRows = result.getVertexTableRows(); + for (VertexTableRow tableRow : tableRows) { + try { + assert (Arrays.asList("1", "2", "3", "4", "5") + .contains(tableRow.getVid().asString())); + assert (Arrays.asList("1", "2", "3", "4", "5") + .contains(tableRow.getString(0))); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + assert (false); + } + } + } + } } diff --git a/client/src/test/resources/docker-compose-casigned.yaml b/client/src/test/resources/docker-compose-casigned.yaml index bfdd1b96d..cf55d12fd 100644 --- a/client/src/test/resources/docker-compose-casigned.yaml +++ b/client/src/test/resources/docker-compose-casigned.yaml @@ -6,10 +6,10 @@ services: USER: root TZ: "${TZ}" command: - - --meta_server_addrs=172.29.1.1:8559 + - --meta_server_addrs=172.29.1.1:9559 - --local_ip=172.29.1.1 - --ws_ip=172.29.1.1 - - --port=8559 + - --port=9559 - --data_path=/data/meta - --log_dir=/logs - --v=0 @@ -19,7 +19,7 @@ services: - --ws_h2_port=11000 - --cert_path=/share/resources/test.derive.crt - --key_path=/share/resources/test.derive.key - - --password_path=/share/resources/test.ca.password + - --ca_path=/share/resources/test.ca.pem - --enable_ssl=true healthcheck: test: ["CMD", "curl", "-f", "http://172.29.1.1:11000/status"] @@ -28,7 +28,7 @@ services: retries: 3 start_period: 20s ports: - - "8559:8559" + - "8559:9559" - 11000 - 11002 volumes: @@ -48,10 +48,10 @@ services: USER: root TZ: "${TZ}" command: - - --meta_server_addrs=172.29.1.1:8559 + - --meta_server_addrs=172.29.1.1:9559 - --local_ip=172.29.2.1 - --ws_ip=172.29.2.1 - - --port=8779 + - --port=9779 - --data_path=/data/storage - --log_dir=/logs - --v=0 @@ -61,7 +61,7 @@ services: - --ws_h2_port=12000 - --cert_path=/share/resources/test.derive.crt - --key_path=/share/resources/test.derive.key - - --password_path=/share/resources/test.ca.password + - --ca_path=/share/resources/test.ca.pem - --enable_ssl=true depends_on: - metad-casigned @@ -72,7 +72,7 @@ services: retries: 3 start_period: 20s ports: - - "8779:8779" + - "8779:9779" - 12000 - 12002 volumes: @@ -92,8 +92,9 @@ services: USER: root TZ: "${TZ}" command: - - --meta_server_addrs=172.29.1.1:8559 - - --port=8669 + - --meta_server_addrs=172.29.1.1:9559 + - --port=9669 + - --local_ip=172.29.3.1 - --ws_ip=172.29.3.1 - --log_dir=/logs - --v=0 @@ -103,7 +104,7 @@ services: - --ws_h2_port=13000 - --cert_path=/share/resources/test.derive.crt - --key_path=/share/resources/test.derive.key - - --password_path=/share/resources/test.ca.password + - --ca_path=/share/resources/test.ca.pem - --enable_ssl=true depends_on: - metad-casigned @@ -114,10 +115,11 @@ services: retries: 3 start_period: 20s ports: - - "8669:8669" + - "8669:9669" - 13000 - 13002 volumes: + - ./data/graph:/data/graph:Z - ./logs/graph:/logs:Z - ./ssl:/share/resources:Z networks: diff --git a/client/src/test/resources/docker-compose-selfsigned.yaml b/client/src/test/resources/docker-compose-selfsigned.yaml index aeac1a60a..8a5a71d84 100644 --- a/client/src/test/resources/docker-compose-selfsigned.yaml +++ b/client/src/test/resources/docker-compose-selfsigned.yaml @@ -6,10 +6,10 @@ services: USER: root TZ: "${TZ}" command: - - --meta_server_addrs=172.29.1.1:8559 - - --local_ip=172.29.1.1 - - --ws_ip=172.29.1.1 - - --port=8559 + - --meta_server_addrs=172.30.1.1:9559 + - --local_ip=172.30.1.1 + - --ws_ip=172.30.1.1 + - --port=9559 - --data_path=/data/meta - --log_dir=/logs - --v=0 @@ -22,22 +22,22 @@ services: - --password_path=/share/resources/test.ca.password - --enable_ssl=true healthcheck: - test: ["CMD", "curl", "-f", "http://172.29.1.1:11000/status"] + test: ["CMD", "curl", "-f", "http://172.30.1.1:11000/status"] interval: 30s timeout: 10s retries: 3 start_period: 20s ports: - - "8559:8559" + - "7559:9559" - 11000 - 11002 volumes: - - ./data/meta:/data/meta:Z + - ./data/meta_self:/data/meta:Z - ./logs/meta:/logs:Z - ./ssl:/share/resources:Z networks: nebula-net-selfsigned: - ipv4_address: 172.29.1.1 + ipv4_address: 172.30.1.1 restart: on-failure cap_add: - SYS_PTRACE @@ -48,10 +48,10 @@ services: USER: root TZ: "${TZ}" command: - - --meta_server_addrs=172.29.1.1:8559 - - --local_ip=172.29.2.1 - - --ws_ip=172.29.2.1 - - --port=8779 + - --meta_server_addrs=172.30.1.1:9559 + - --local_ip=172.30.2.1 + - --ws_ip=172.30.2.1 + - --port=9779 - --data_path=/data/storage - --log_dir=/logs - --v=0 @@ -66,22 +66,22 @@ services: depends_on: - metad-selfsigned healthcheck: - test: ["CMD", "curl", "-f", "http://172.29.2.1:12000/status"] + test: ["CMD", "curl", "-f", "http://172.30.2.1:12000/status"] interval: 30s timeout: 10s retries: 3 start_period: 20s ports: - - "8779:8779" + - "7779:9779" - 12000 - 12002 volumes: - - ./data/storage:/data/storage:Z + - ./data/storage_self:/data/storage:Z - ./logs/storage:/logs:Z - ./ssl:/share/resources:Z networks: nebula-net-selfsigned: - ipv4_address: 172.29.2.1 + ipv4_address: 172.30.2.1 restart: on-failure cap_add: - SYS_PTRACE @@ -92,9 +92,9 @@ services: USER: root TZ: "${TZ}" command: - - --meta_server_addrs=172.29.1.1:8559 - - --port=8669 - - --ws_ip=172.29.3.1 + - --meta_server_addrs=172.30.1.1:9559 + - --port=9669 + - --ws_ip=172.30.3.1 - --log_dir=/logs - --v=0 - --minloglevel=0 @@ -108,21 +108,22 @@ services: depends_on: - metad-selfsigned healthcheck: - test: ["CMD", "curl", "-f", "http://172.29.3.1:13000/status"] + test: ["CMD", "curl", "-f", "http://172.30.3.1:13000/status"] interval: 30s timeout: 10s retries: 3 start_period: 20s ports: - - "8669:8669" + - "7669:9669" - 13000 - 13002 volumes: + - ./data/graph_self:/data/graph:Z - ./logs/graph:/logs:Z - ./ssl:/share/resources:Z networks: nebula-net-selfsigned: - ipv4_address: 172.29.3.1 + ipv4_address: 172.30.3.1 restart: on-failure cap_add: - SYS_PTRACE @@ -132,4 +133,4 @@ networks: ipam: driver: default config: - - subnet: 172.29.0.0/16 + - subnet: 172.30.0.0/16