Tessera Orion-mode privacy ATs (#2166)

* Refactored privacy ATs to use both Orion and Tessera.

Signed-off-by: Mark Terry <mark.terry@consensys.net>
This commit is contained in:
mark-terry
2021-06-02 10:34:28 +10:00
committed by GitHub
parent 82dcdf219c
commit 3e86423457
55 changed files with 1128 additions and 233 deletions

View File

@@ -42,4 +42,6 @@ dependencies {
implementation 'org.assertj:assertj-core'
implementation 'org.mockito:mockito-core'
implementation 'org.web3j:core'
implementation 'org.testcontainers:testcontainers'
}

View File

@@ -12,13 +12,13 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.orion.testutil;
package org.hyperledger.enclave.testutil;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
public class OrionConfiguration {
public class EnclaveConfiguration {
private final Path[] publicKeys;
private final Path[] privateKeys;
@@ -26,8 +26,10 @@ public class OrionConfiguration {
private final List<String> otherNodes = new ArrayList<>();
private final boolean clearKnownNodes;
private final String storage;
private final String name;
public OrionConfiguration(
public EnclaveConfiguration(
final String name,
final Path[] publicKeys,
final Path[] privateKeys,
final Path tempDir,
@@ -41,6 +43,7 @@ public class OrionConfiguration {
this.otherNodes.addAll(otherNodes);
this.clearKnownNodes = clearKnownNodes;
this.storage = storage;
this.name = name;
}
public Path[] getPublicKeys() {
@@ -70,4 +73,8 @@ public class OrionConfiguration {
public String getStorage() {
return storage;
}
public String getName() {
return name;
}
}

View File

@@ -12,18 +12,18 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.orion.testutil;
package org.hyperledger.enclave.testutil;
public class OrionKeyConfiguration {
public class EnclaveKeyConfiguration {
private final String[] pubKeyPaths;
private final String[] privKeyPaths;
public OrionKeyConfiguration(final String pubKeyPath, final String privKeyPath) {
public EnclaveKeyConfiguration(final String pubKeyPath, final String privKeyPath) {
this.pubKeyPaths = new String[] {pubKeyPath};
this.privKeyPaths = new String[] {privKeyPath};
}
public OrionKeyConfiguration(final String[] pubKeyPaths, final String[] privKeyPaths) {
public EnclaveKeyConfiguration(final String[] pubKeyPaths, final String[] privKeyPaths) {
this.pubKeyPaths = pubKeyPaths;
this.privKeyPaths = privKeyPaths;
}

View File

@@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.orion.testutil;
package org.hyperledger.enclave.testutil;
import java.io.BufferedReader;
import java.io.IOException;
@@ -30,7 +30,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes;
public class OrionKeyUtils {
public class EnclaveKeyUtils {
private static final Logger LOG = LogManager.getLogger();
/**
@@ -42,7 +42,7 @@ public class OrionKeyUtils {
* @throws IOException throws if key not found
*/
public static String loadKey(final String keyFileName) throws IOException {
InputStream is = OrionKeyUtils.class.getResourceAsStream("/" + keyFileName);
InputStream is = EnclaveKeyUtils.class.getResourceAsStream("/" + keyFileName);
InputStreamReader streamReader = new InputStreamReader(is, StandardCharsets.UTF_8);
try (BufferedReader reader = new BufferedReader(streamReader)) {
return reader.readLine();

View File

@@ -0,0 +1,42 @@
/*
* Copyright ConsenSys AG.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.enclave.testutil;
import java.net.URI;
import java.nio.file.Path;
import java.util.List;
public interface EnclaveTestHarness {
void start();
void stop();
void close();
List<Path> getPublicKeyPaths();
String getDefaultPublicKey();
List<String> getPublicKeys();
URI clientUrl();
URI nodeUrl();
void addOtherNode(final URI otherNode);
EnclaveType getEnclaveType();
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright ConsenSys AG.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.enclave.testutil;
public enum EnclaveType {
ORION,
TESSERA
}

View File

@@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.orion.testutil;
package org.hyperledger.enclave.testutil;
import static com.google.common.io.Files.readLines;
@@ -32,11 +32,11 @@ import okhttp3.HttpUrl;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class OrionTestHarness {
public class OrionTestHarness implements EnclaveTestHarness {
private static final Logger LOG = LogManager.getLogger();
private final Orion orion;
private final OrionConfiguration orionConfiguration;
private final EnclaveConfiguration enclaveConfiguration;
private Config config;
@@ -44,25 +44,23 @@ public class OrionTestHarness {
protected static final String HOST = "127.0.0.1";
protected OrionTestHarness(final OrionConfiguration orionConfiguration) {
this.orionConfiguration = orionConfiguration;
protected OrionTestHarness(final EnclaveConfiguration enclaveConfiguration) {
this.enclaveConfiguration = enclaveConfiguration;
this.orion = new Orion();
}
public Orion getOrion() {
return orion;
}
@Override
public void start() {
if (!isRunning) {
config = buildConfig();
orion.run(config, orionConfiguration.isClearKnownNodes());
orion.run(config, enclaveConfiguration.isClearKnownNodes());
isRunning = true;
LOG.info("Orion node port: {}", orion.nodePort());
LOG.info("Orion client port: {}", orion.clientPort());
}
}
@Override
public void stop() {
if (isRunning) {
orion.stop();
@@ -70,6 +68,7 @@ public class OrionTestHarness {
}
}
@Override
public void close() {
stop();
try {
@@ -79,14 +78,21 @@ public class OrionTestHarness {
}
}
@Override
public List<Path> getPublicKeyPaths() {
return config.publicKeys();
}
public Config getConfig() {
return config;
}
@Override
public String getDefaultPublicKey() {
return config.publicKeys().stream().map(OrionTestHarness::readFile).findFirst().orElseThrow();
}
@Override
public List<String> getPublicKeys() {
return config.publicKeys().stream()
.map(OrionTestHarness::readFile)
@@ -102,6 +108,7 @@ public class OrionTestHarness {
}
}
@Override
public URI clientUrl() {
final HttpUrl httpUrl =
new HttpUrl.Builder().scheme("http").host(HOST).port(orion.clientPort()).build();
@@ -109,6 +116,7 @@ public class OrionTestHarness {
return URI.create(httpUrl.toString());
}
@Override
public URI nodeUrl() {
final HttpUrl httpUrl =
new HttpUrl.Builder().scheme("http").host(HOST).port(orion.nodePort()).build();
@@ -116,8 +124,14 @@ public class OrionTestHarness {
return URI.create(httpUrl.toString());
}
@Override
public void addOtherNode(final URI otherNode) {
orionConfiguration.addOtherNode(otherNode.toString());
enclaveConfiguration.addOtherNode(otherNode.toString());
}
@Override
public EnclaveType getEnclaveType() {
return EnclaveType.ORION;
}
private Config buildConfig() {
@@ -135,21 +149,23 @@ public class OrionTestHarness {
+ HOST
+ "\"\n"
+ "storage = \""
+ orionConfiguration.getStorage()
+ enclaveConfiguration.getStorage()
+ "\"\n"
+ "publickeys = ["
+ joinPathsAsTomlListEntry(orionConfiguration.getPublicKeys())
+ joinPathsAsTomlListEntry(enclaveConfiguration.getPublicKeys())
+ "]\n"
+ "privatekeys = ["
+ joinPathsAsTomlListEntry(orionConfiguration.getPrivateKeys())
+ joinPathsAsTomlListEntry(enclaveConfiguration.getPrivateKeys())
+ "]\n"
+ "workdir= \""
+ orionConfiguration.getTempDir().toString()
+ enclaveConfiguration.getTempDir().toString()
+ "\"\n";
if (orionConfiguration.getOtherNodes().size() != 0) {
if (enclaveConfiguration.getOtherNodes().size() != 0) {
confString +=
"othernodes = [" + joinStringsAsTomlListEntry(orionConfiguration.getOtherNodes()) + "]\n";
"othernodes = ["
+ joinStringsAsTomlListEntry(enclaveConfiguration.getOtherNodes())
+ "]\n";
}
// @formatter:on

View File

@@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.orion.testutil;
package org.hyperledger.enclave.testutil;
import static org.apache.tuweni.io.file.Files.copyResource;
@@ -26,8 +26,9 @@ public class OrionTestHarnessFactory {
private static final String storage = "memory";
public static OrionTestHarness create(
final Path tempDir, final OrionKeyConfiguration orionConfig) {
final String name, final Path tempDir, final EnclaveKeyConfiguration orionConfig) {
return create(
name,
tempDir,
orionConfig.getPubKeyPaths(),
orionConfig.getPrivKeyPaths(),
@@ -35,6 +36,7 @@ public class OrionTestHarnessFactory {
}
public static OrionTestHarness create(
final String name,
final Path tempDir,
final String[] pubKeyPaths,
final String[] privKeyPaths,
@@ -62,15 +64,16 @@ public class OrionTestHarnessFactory {
})
.toArray(Path[]::new);
return create(tempDir, pubKeys, privKeys, othernodes);
return create(name, tempDir, pubKeys, privKeys, othernodes);
}
public static OrionTestHarness create(
final String name,
final Path tempDir,
final Path[] key1pubs,
final Path[] key1keys,
final List<String> othernodes) {
return new OrionTestHarness(
new OrionConfiguration(key1pubs, key1keys, tempDir, othernodes, false, storage));
new EnclaveConfiguration(name, key1pubs, key1keys, tempDir, othernodes, false, storage));
}
}

View File

@@ -0,0 +1,284 @@
/*
* Copyright ConsenSys AG.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.enclave.testutil;
import static com.google.common.io.Files.readLines;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import com.google.common.base.Charsets;
import io.vertx.core.json.JsonArray;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.assertj.core.util.Files;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.MountableFile;
public class TesseraTestHarness implements EnclaveTestHarness {
private static final Logger LOG = LogManager.getLogger();
private final EnclaveConfiguration enclaveConfiguration;
private boolean isRunning;
private URI nodeURI;
private URI q2TUri;
private URI thirdPartyUri;
private final String tesseraVersion = "latest";
private final int thirdPartyPort = 9081;
private final int q2TPort = 9082;
public static final int p2pPort = 9001;
private final String containerKeyDir = "/tmp/keys/";
@SuppressWarnings("rawtypes")
private GenericContainer tesseraContainer;
private final Optional<Network> containerNetwork;
private final String containerName;
protected TesseraTestHarness(
final EnclaveConfiguration enclaveConfiguration, final Optional<Network> containerNetwork) {
this.enclaveConfiguration = enclaveConfiguration;
this.containerNetwork = containerNetwork;
this.containerName = enclaveConfiguration.getName();
Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
}
@Override
public void start() {
if (!isRunning) {
final File tempFolder = Files.newTemporaryFolder();
LOG.info("Temporary directory: " + tempFolder.getAbsolutePath());
final String configFile = createConfigFile(enclaveConfiguration.getName());
tesseraContainer = buildTesseraContainer(configFile);
containerNetwork.ifPresent(network -> addNetwork(tesseraContainer, containerName, network));
tesseraContainer.start();
isRunning = true;
try {
final String host = "http://" + tesseraContainer.getHost();
nodeURI = new URI(host + ":" + tesseraContainer.getMappedPort(p2pPort));
LOG.info("Tessera node URI: {}", nodeURI);
q2TUri = new URI(host + ':' + tesseraContainer.getMappedPort(q2TPort));
LOG.info("Tessera client URI: {}", q2TUri);
thirdPartyUri = new URI(host + ':' + tesseraContainer.getMappedPort(thirdPartyPort));
LOG.info("Tessera thirdParty URI: {}", thirdPartyUri);
} catch (final URISyntaxException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void stop() {
if (isRunning) {
tesseraContainer.stop();
isRunning = false;
}
}
@Override
public void close() {
stop();
}
@Override
public List<Path> getPublicKeyPaths() {
return Arrays.asList(enclaveConfiguration.getPublicKeys());
}
@Override
public String getDefaultPublicKey() {
return readFile(enclaveConfiguration.getPublicKeys()[0]);
}
@Override
public List<String> getPublicKeys() {
return Arrays.stream(enclaveConfiguration.getPublicKeys())
.map(TesseraTestHarness::readFile)
.collect(Collectors.toList());
}
private static String readFile(final Path path) {
try {
return readLines(path.toFile(), Charsets.UTF_8).get(0);
} catch (final IOException e) {
e.printStackTrace();
return "";
}
}
@Override
public URI clientUrl() {
return q2TUri;
}
@Override
public URI nodeUrl() {
return nodeURI;
}
@Override
public void addOtherNode(final URI otherNode) {
enclaveConfiguration.addOtherNode(otherNode.toString());
}
@Override
public EnclaveType getEnclaveType() {
return EnclaveType.TESSERA;
}
private String createConfigFile(final String nodeName) {
// create a config file
// @formatter:off
String confString =
"{\n"
+ " \"mode\" : \"orion\",\n"
+ " \"encryptor\":{\n"
+ " \"type\":\"NACL\",\n"
+ " \"properties\":{\n"
+ " }\n"
+ " },\n"
+ " \"useWhiteList\": false,\n"
+ " \"jdbc\": {\n"
+ " \"username\": \"sa\",\n"
+ " \"password\": \"\",\n"
+ " \"url\": \"jdbc:h2:/tmp/db;MODE=Oracle;TRACE_LEVEL_SYSTEM_OUT=0\",\n"
+ " \"autoCreateTables\": true\n"
+ " },\n"
+ " \"serverConfigs\":[\n"
+ " {\n"
+ " \"app\":\"ThirdParty\",\n"
+ " \"enabled\": true,\n"
+ " \"serverAddress\": \"http://"
+ nodeName
+ ":"
+ thirdPartyPort
+ "\",\n"
+ " \"cors\" : {\n"
+ " \"allowedMethods\" : [\"GET\", \"OPTIONS\"],\n"
+ " \"allowedOrigins\" : [\"*\"]\n"
+ " },\n"
+ " \"communicationType\" : \"REST\"\n"
+ " },\n"
+ " {\n"
+ " \"app\":\"Q2T\",\n"
+ " \"enabled\": true,\n"
+ " \"serverAddress\":\"http://"
+ nodeName
+ ":"
+ q2TPort
+ "\",\n"
+ " \"communicationType\" : \"REST\"\n"
+ " },\n"
+ " {\n"
+ " \"app\":\"P2P\",\n"
+ " \"enabled\": true,\n"
+ " \"serverAddress\":\"http://"
+ nodeName
+ ":"
+ p2pPort
+ "\",\n"
+ " \"communicationType\" : \"REST\"\n"
+ " }\n"
+ " ],\n"
+ " \"keys\": {\n"
+ " \"passwords\": [],\n"
+ " \"keyData\": "
+ buildKeyConfig()
+ "\n"
+ " },\n"
+ " \"alwaysSendTo\": []";
if (enclaveConfiguration.getOtherNodes().size() != 0) {
confString +=
",\n"
+ " \"peer\": [\n"
+ " {\n"
+ " \"url\": \""
+ enclaveConfiguration.getOtherNodes().get(0)
+ "\"\n"
+ " }\n"
+ " ]";
} else {
confString += ",\n" + " \"peer\": []";
}
confString += "\n}";
final File configFile = Files.newTemporaryFile();
try {
final FileWriter fw = new FileWriter(configFile, StandardCharsets.UTF_8);
fw.write(confString);
fw.close();
} catch (final IOException e) {
throw new RuntimeException(e);
}
return configFile.getAbsolutePath();
}
private String buildKeyConfig() {
final JsonArray keyArray = new JsonArray();
final List<Path> pubKeysPaths = Arrays.asList(enclaveConfiguration.getPublicKeys());
final List<Path> privKeyPaths = Arrays.asList(enclaveConfiguration.getPrivateKeys());
for (int count = 0; count < pubKeysPaths.size(); count++) {
final HashMap<String, String> stringStringHashMap = new HashMap<>();
stringStringHashMap.put(
"publicKeyPath", containerKeyDir + pubKeysPaths.get(count).getFileName());
stringStringHashMap.put(
"privateKeyPath", containerKeyDir + privKeyPaths.get(count).getFileName());
keyArray.add(stringStringHashMap);
}
return keyArray.toString();
}
@SuppressWarnings("rawtypes")
private GenericContainer buildTesseraContainer(final String configFilePath) {
final String containerConfigFilePath = "/tmp/config.json";
final String keyDir = enclaveConfiguration.getTempDir().toString();
return new GenericContainer<>("quorumengineering/tessera:" + tesseraVersion)
.withCopyFileToContainer(MountableFile.forHostPath(configFilePath), containerConfigFilePath)
.withFileSystemBind(keyDir, containerKeyDir)
.withCommand("--configfile " + containerConfigFilePath)
.withExposedPorts(p2pPort, q2TPort, thirdPartyPort)
.waitingFor(Wait.forHttp("/upcheck").withMethod("GET").forStatusCode(200));
}
@SuppressWarnings("rawtypes")
private void addNetwork(
final GenericContainer container, final String containerName, final Network network) {
container.withNetwork(network).withNetworkAliases(containerName);
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright ConsenSys AG.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.enclave.testutil;
import static org.apache.tuweni.io.file.Files.copyResource;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.jetbrains.annotations.NotNull;
import org.testcontainers.containers.Network;
public class TesseraTestHarnessFactory {
private static final String storage = "memory";
public static TesseraTestHarness create(
final String name,
final Path tempDir,
final EnclaveKeyConfiguration enclaveConfig,
final Optional<Network> containerNetwork) {
return create(
name,
tempDir,
enclaveConfig.getPubKeyPaths(),
enclaveConfig.getPrivKeyPaths(),
Collections.emptyList(),
containerNetwork);
}
public static TesseraTestHarness create(
final String name,
final Path tempDir,
final String[] pubKeyPaths,
final String[] privKeyPaths,
final List<String> othernodes,
final Optional<Network> containerNetwork) {
final Path[] pubKeys = stringArrayToPathArray(tempDir, pubKeyPaths);
final Path[] privKeys = stringArrayToPathArray(tempDir, privKeyPaths);
return create(name, tempDir, pubKeys, privKeys, othernodes, containerNetwork);
}
public static TesseraTestHarness create(
final String name,
final Path tempDir,
final Path[] key1pubs,
final Path[] key1keys,
final List<String> othernodes,
final Optional<Network> containerNetwork) {
return new TesseraTestHarness(
new EnclaveConfiguration(name, key1pubs, key1keys, tempDir, othernodes, false, storage),
containerNetwork);
}
@NotNull
private static Path[] stringArrayToPathArray(final Path tempDir, final String[] privKeyPaths) {
return Arrays.stream(privKeyPaths)
.map(
(pk) -> {
try {
return copyResource(pk, tempDir.resolve(pk));
} catch (final IOException e) {
throw new RuntimeException(e);
}
})
.toArray(Path[]::new);
}
}