[NC-1742] Added host whitelist for Json-RPC. (#295)

mark-terry 6 years ago committed by GitHub
parent 0d63533191
commit 3bcdc047a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNodeFactory.java
  2. 15
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcConfiguration.java
  3. 45
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpService.java
  4. 169
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java
  5. 16
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceRpcApisTest.java
  6. 218
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java
  7. 12
      pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java
  8. 70
      pantheon/src/main/java/tech/pegasys/pantheon/cli/custom/JsonRPCWhitelistHostsProperty.java
  9. 4
      pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java
  10. 56
      pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java
  11. 11
      quickstart/src/test/java/tech/pegasys/pantheon/tests/quickstart/DockerQuickstartTest.java

@ -13,6 +13,7 @@
package tech.pegasys.pantheon.tests.acceptance.dsl.node;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueRpcApis.CLIQUE;
@ -154,6 +155,7 @@ public class PantheonNodeFactory {
final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault();
config.setEnabled(true);
config.setPort(0);
config.setHostsWhitelist(singletonList("*"));
return config;
}

@ -20,7 +20,7 @@ import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
public class JsonRpcConfiguration {
public static final String DEFAULT_JSON_RPC_HOST = "127.0.0.1";
private static final String DEFAULT_JSON_RPC_HOST = "127.0.0.1";
public static final int DEFAULT_JSON_RPC_PORT = 8545;
private boolean enabled;
@ -28,6 +28,7 @@ public class JsonRpcConfiguration {
private String host;
private Collection<String> corsAllowedDomains = Collections.emptyList();
private Collection<RpcApi> rpcApis;
private Collection<String> hostsWhitelist = Collections.singletonList("localhost");
public static JsonRpcConfiguration createDefault() {
final JsonRpcConfiguration config = new JsonRpcConfiguration();
@ -87,6 +88,14 @@ public class JsonRpcConfiguration {
rpcApis.add(rpcApi);
}
public Collection<String> getHostsWhitelist() {
return Collections.unmodifiableCollection(this.hostsWhitelist);
}
public void setHostsWhitelist(final Collection<String> hostsWhitelist) {
this.hostsWhitelist = hostsWhitelist;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
@ -94,6 +103,7 @@ public class JsonRpcConfiguration {
.add("port", port)
.add("host", host)
.add("corsAllowedDomains", corsAllowedDomains)
.add("hostsWhitelist", hostsWhitelist)
.add("rpcApis", rpcApis)
.toString();
}
@ -111,11 +121,12 @@ public class JsonRpcConfiguration {
&& port == that.port
&& Objects.equal(host, that.host)
&& Objects.equal(corsAllowedDomains, that.corsAllowedDomains)
&& Objects.equal(hostsWhitelist, that.hostsWhitelist)
&& Objects.equal(rpcApis, that.rpcApis);
}
@Override
public int hashCode() {
return Objects.hashCode(enabled, port, host, corsAllowedDomains, rpcApis);
return Objects.hashCode(enabled, port, host, corsAllowedDomains, hostsWhitelist, rpcApis);
}
}

@ -13,6 +13,7 @@
package tech.pegasys.pantheon.ethereum.jsonrpc;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Streams.stream;
import static java.util.stream.Collectors.toList;
import static tech.pegasys.pantheon.util.NetworkUtility.urlForSocketAddress;
@ -38,13 +39,17 @@ import java.net.SocketException;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.concurrent.CompletableFuture;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.CompositeFuture;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServer;
@ -113,6 +118,10 @@ public class JsonRpcHttpService {
// Handle json rpc requests
final Router router = Router.router(vertx);
// Verify Host header to avoid rebind attack.
router.route().handler(checkWhitelistHostHeader());
router
.route()
.handler(
@ -161,6 +170,42 @@ public class JsonRpcHttpService {
return resultFuture;
}
private Handler<RoutingContext> checkWhitelistHostHeader() {
return event -> {
Optional<String> hostHeader = getAndValidateHostHeader(event);
if (config.getHostsWhitelist().contains("*")
|| (hostHeader.isPresent() && hostIsInWhitelist(hostHeader))) {
event.next();
} else {
event
.response()
.setStatusCode(403)
.putHeader("Content-Type", "application/json; charset=utf-8")
.end("{\"message\":\"Host not authorized.\"}");
}
};
}
private Optional<String> getAndValidateHostHeader(final RoutingContext event) {
Iterable<String> splitHostHeader = Splitter.on(':').split(event.request().host());
long hostPieces = stream(splitHostHeader).count();
if (hostPieces > 1) {
// If the host contains a colon, verify the host is correctly formed - host [ ":" port ]
if (hostPieces > 2 || !Iterables.get(splitHostHeader, 1).matches("\\d{1,5}+")) {
return Optional.empty();
}
}
return Optional.ofNullable(Iterables.get(splitHostHeader, 0));
}
private boolean hostIsInWhitelist(final Optional<String> hostHeader) {
return config
.getHostsWhitelist()
.stream()
.anyMatch(
whitelistEntry -> whitelistEntry.toLowerCase().equals(hostHeader.get().toLowerCase()));
}
public CompletableFuture<?> stop() {
if (httpServer == null) {
return CompletableFuture.completedFuture(null);

@ -0,0 +1,169 @@
/*
* Copyright 2018 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.
*/
package tech.pegasys.pantheon.ethereum.jsonrpc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import tech.pegasys.pantheon.config.StubGenesisConfigOptions;
import tech.pegasys.pantheon.ethereum.blockcreation.EthHashMiningCoordinator;
import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.core.TransactionPool;
import tech.pegasys.pantheon.ethereum.eth.EthProtocol;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.filter.FilterManager;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.vertx.core.Vertx;
import io.vertx.core.json.Json;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class JsonRpcHttpServiceHostWhitelistTest {
@ClassRule public static final TemporaryFolder folder = new TemporaryFolder();
protected static final Vertx vertx = Vertx.vertx();
private static Map<String, JsonRpcMethod> rpcMethods;
private static JsonRpcHttpService service;
private static OkHttpClient client;
private static String baseUrl;
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static final String CLIENT_VERSION = "TestClientVersion/0.1.0";
private static final int CHAIN_ID = 123;
private static final Collection<RpcApi> JSON_RPC_APIS =
Arrays.asList(RpcApis.ETH, RpcApis.NET, RpcApis.WEB3);
private final JsonRpcConfiguration jsonRpcConfig = createJsonRpcConfig();
private final List<String> hostsWhitelist = Arrays.asList("ally", "friend");
@Before
public void initServerAndClient() throws Exception {
P2PNetwork peerDiscoveryMock = mock(P2PNetwork.class);
BlockchainQueries blockchainQueries = mock(BlockchainQueries.class);
Synchronizer synchronizer = mock(Synchronizer.class);
final Set<Capability> supportedCapabilities = new HashSet<>();
supportedCapabilities.add(EthProtocol.ETH62);
supportedCapabilities.add(EthProtocol.ETH63);
rpcMethods =
spy(
new JsonRpcMethodsFactory()
.methods(
CLIENT_VERSION,
peerDiscoveryMock,
blockchainQueries,
synchronizer,
MainnetProtocolSchedule.fromConfig(
new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID)),
mock(FilterManager.class),
mock(TransactionPool.class),
mock(EthHashMiningCoordinator.class),
new NoOpMetricsSystem(),
supportedCapabilities,
JSON_RPC_APIS));
service = createJsonRpcHttpService();
service.start().join();
client = new OkHttpClient();
baseUrl = service.url();
}
private JsonRpcHttpService createJsonRpcHttpService() throws Exception {
return new JsonRpcHttpService(
vertx, folder.newFolder().toPath(), jsonRpcConfig, new NoOpMetricsSystem(), rpcMethods);
}
private static JsonRpcConfiguration createJsonRpcConfig() {
final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault();
config.setPort(0);
return config;
}
@After
public void shutdownServer() {
service.stop().join();
}
@Test
public void requestWithDefaultHeaderAndDefaultConfigIsAccepted() throws IOException {
assertThat(doRequest("localhost:50012")).isEqualTo(200);
}
@Test
public void requestWithEmptyHeaderAndDefaultConfigIsRejected() throws IOException {
assertThat(doRequest("")).isEqualTo(403);
}
@Test
public void requestWithAnyHostnameAndWildcardConfigIsAccepted() throws IOException {
jsonRpcConfig.setHostsWhitelist(Collections.singletonList("*"));
assertThat(doRequest("ally")).isEqualTo(200);
assertThat(doRequest("foe")).isEqualTo(200);
}
@Test
public void requestWithWhitelistedHostIsAccepted() throws IOException {
jsonRpcConfig.setHostsWhitelist(hostsWhitelist);
assertThat(doRequest("ally")).isEqualTo(200);
assertThat(doRequest("ally:12345")).isEqualTo(200);
assertThat(doRequest("friend")).isEqualTo(200);
}
@Test
public void requestWithUnknownHostIsRejected() throws IOException {
jsonRpcConfig.setHostsWhitelist(hostsWhitelist);
assertThat(doRequest("foe")).isEqualTo(403);
}
private int doRequest(final String hostname) throws IOException {
final RequestBody body =
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode("123") + ",\"method\":\"net_version\"}");
Request build =
new Request.Builder().post(body).url(baseUrl).addHeader("Host", hostname).build();
return client.newCall(build).execute().code();
}
@Test
public void requestWithMalformedHostIsRejected() throws IOException {
jsonRpcConfig.setHostsWhitelist(hostsWhitelist);
assertThat(doRequest("ally:friend")).isEqualTo(403);
assertThat(doRequest("ally:123456")).isEqualTo(403);
assertThat(doRequest("ally:friend:1234")).isEqualTo(403);
}
}

@ -87,9 +87,8 @@ public class JsonRpcHttpServiceRpcApisTest {
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"net_version\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
}
}
@ -102,9 +101,8 @@ public class JsonRpcHttpServiceRpcApisTest {
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"net_version\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
}
}
@ -117,9 +115,8 @@ public class JsonRpcHttpServiceRpcApisTest {
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"net_version\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -137,9 +134,8 @@ public class JsonRpcHttpServiceRpcApisTest {
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"net_version\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
}
}
@ -188,4 +184,8 @@ public class JsonRpcHttpServiceRpcApisTest {
baseUrl = jsonRpcHttpService.url();
return jsonRpcHttpService;
}
private Request buildRequest(final RequestBody body) {
return new Request.Builder().post(body).url(baseUrl).build();
}
}

@ -131,13 +131,13 @@ public class JsonRpcHttpServiceTest {
baseUrl = service.url();
}
protected static JsonRpcHttpService createJsonRpcHttpService(final JsonRpcConfiguration config)
private static JsonRpcHttpService createJsonRpcHttpService(final JsonRpcConfiguration config)
throws Exception {
return new JsonRpcHttpService(
vertx, folder.newFolder().toPath(), config, new NoOpMetricsSystem(), rpcMethods);
}
protected static JsonRpcHttpService createJsonRpcHttpService() throws Exception {
private static JsonRpcHttpService createJsonRpcHttpService() throws Exception {
return new JsonRpcHttpService(
vertx,
folder.newFolder().toPath(),
@ -146,9 +146,10 @@ public class JsonRpcHttpServiceTest {
rpcMethods);
}
protected static JsonRpcConfiguration createJsonRpcConfig() {
private static JsonRpcConfiguration createJsonRpcConfig() {
final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault();
config.setPort(0);
config.setHostsWhitelist(Collections.singletonList("*"));
return config;
}
@ -170,18 +171,14 @@ public class JsonRpcHttpServiceTest {
@Test
public void http404() throws Exception {
final Request request = new Request.Builder().get().url(baseUrl + "/foo").build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildGetRequest("/foo")).execute()) {
assertThat(resp.code()).isEqualTo(404);
}
}
@Test
public void handleEmptyRequest() throws Exception {
final Request request = new Request.Builder().get().url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildGetRequest("")).execute()) {
assertThat(resp.code()).isEqualTo(201);
}
}
@ -229,9 +226,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.header("Content-Type")).isEqualTo("application/json");
}
}
@ -245,9 +241,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -265,9 +260,8 @@ public class JsonRpcHttpServiceTest {
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"net_version\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -285,9 +279,8 @@ public class JsonRpcHttpServiceTest {
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"eth_accounts\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -307,9 +300,8 @@ public class JsonRpcHttpServiceTest {
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"net_peerCount\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -336,9 +328,8 @@ public class JsonRpcHttpServiceTest {
+ ","
+ params
+ ",\"method\":\"eth_getUncleCountByBlockHash\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String jsonStr = resp.body().string();
@ -365,9 +356,8 @@ public class JsonRpcHttpServiceTest {
+ ","
+ params
+ ",\"method\":\"eth_getUncleCountByBlockHash\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String jsonStr = resp.body().string();
@ -395,9 +385,8 @@ public class JsonRpcHttpServiceTest {
+ ","
+ params
+ ",\"method\":\"eth_getUncleCountByBlockNumber\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -424,9 +413,8 @@ public class JsonRpcHttpServiceTest {
+ ","
+ params
+ ",\"method\":\"eth_getUncleCountByBlockNumber\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -452,9 +440,8 @@ public class JsonRpcHttpServiceTest {
+ ","
+ params
+ ",\"method\":\"eth_getUncleCountByBlockNumber\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -481,9 +468,8 @@ public class JsonRpcHttpServiceTest {
+ ","
+ params
+ ",\"method\":\"eth_getUncleCountByBlockNumber\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -506,9 +492,8 @@ public class JsonRpcHttpServiceTest {
+ ","
+ params
+ ",\"method\":\"eth_getUncleCountByBlockNumber\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -530,9 +515,8 @@ public class JsonRpcHttpServiceTest {
+ ","
+ params
+ ",\"method\":\"eth_getUncleCountByBlockNumber\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -551,9 +535,8 @@ public class JsonRpcHttpServiceTest {
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"net_peerCount\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -583,9 +566,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBalance\", \"params\": [\""
+ address
+ "\",\"latest\"]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -616,9 +598,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBalance\", \"params\": [\""
+ address
+ "\",\"latest\"]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -648,9 +629,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBalance\", \"params\": [\""
+ address
+ "\",\"earliest\"]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -683,9 +663,8 @@ public class JsonRpcHttpServiceTest {
+ "\",\"0x"
+ Long.toString(blockNumber, 16)
+ "\"]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -711,12 +690,11 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBlockByHash\", \"params\": [\""
+ blockHashString
+ "\",true]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
// Setup mocks
when(blockchainQueries.blockByHash(eq(blockHash))).thenReturn(Optional.empty());
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -747,9 +725,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBlockByHash\", \"params\": [\""
+ blockHash
+ "\",true]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -780,9 +757,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBlockByHash\", \"params\": [\""
+ blockHash
+ "\",false]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -803,13 +779,12 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"eth_getBlockByHash\", \"params\": [true]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
// Setup mocks
when(blockchainQueries.blockByHash(ArgumentMatchers.isA(Hash.class)))
.thenReturn(Optional.empty());
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -832,9 +807,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBlockByHash\", \"params\": [\""
+ blockHashString
+ "\"]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -856,9 +830,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBlockByHash\", \"params\": [\""
+ blockHashString
+ "\",true]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -880,9 +853,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBlockByHash\", \"params\": [\""
+ blockHashString
+ "\",true]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -905,9 +877,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBlockByHash\", \"params\": [\""
+ blockHashString
+ "\",{}]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -926,9 +897,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"eth_getBlockByHash\", \"params\": []}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -947,9 +917,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"eth_getBlockByHash\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -978,9 +947,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBlockByNumber\", \"params\": [\"0x"
+ Long.toString(number, 16)
+ "\",true]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -1011,9 +979,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"eth_getBlockByNumber\", \"params\": [\"0x"
+ Long.toString(number, 16)
+ "\",false]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -1035,9 +1002,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"eth_getBlockByNumber\", \"params\": [\"bla\",false]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
// Check general format of result
final String respBody = resp.body().string();
@ -1065,9 +1031,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"eth_getBlockByNumber\", \"params\": [\"earliest\",true]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -1088,7 +1053,6 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"eth_getBlockByNumber\", \"params\": [\"0x0\",true]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
// Setup mocks to return a block
final BlockDataGenerator gen = new BlockDataGenerator();
@ -1097,7 +1061,7 @@ public class JsonRpcHttpServiceTest {
blockWithMetadata(block);
when(blockchainQueries.blockByNumber(eq(0L))).thenReturn(Optional.of(blockWithMetadata));
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -1118,7 +1082,6 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"eth_getBlockByNumber\", \"params\": [\"latest\",true]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
// Setup mocks to return a block
final BlockDataGenerator gen = new BlockDataGenerator();
@ -1128,7 +1091,7 @@ public class JsonRpcHttpServiceTest {
when(blockchainQueries.headBlockNumber()).thenReturn(0L);
when(blockchainQueries.blockByNumber(eq(0L))).thenReturn(Optional.of(blockWithMetadata));
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -1149,9 +1112,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"eth_getBlockByNumber\", \"params\": [\"pending\",true]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -1172,9 +1134,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"web3_clientVersion\", \"params\": [1,2,3]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -1191,9 +1152,8 @@ public class JsonRpcHttpServiceTest {
final RequestBody body =
RequestBody.create(
JSON, "{\"id\":" + Json.encode(id) + ",\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
final JsonObject json = new JsonObject(resp.body().string());
testHelper.assertValidJsonRpcResult(json, id);
@ -1207,9 +1167,8 @@ public class JsonRpcHttpServiceTest {
// No id field is present - marking this as a notification
final RequestBody body =
RequestBody.create(JSON, "{\"jsonrpc\":\"2.0\",\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
// Notifications return an empty response
assertThat(resp.code()).isEqualTo(200);
final String resBody = resp.body().string();
@ -1223,9 +1182,8 @@ public class JsonRpcHttpServiceTest {
final RequestBody body =
RequestBody.create(
JSON, "{\"jsonrpc\":\"2.0\",\"id\":null,\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -1245,9 +1203,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
// An empty string is still a string, so should be a valid id
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
@ -1268,9 +1225,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -1293,9 +1249,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -1320,9 +1275,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -1342,9 +1296,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -1360,9 +1313,8 @@ public class JsonRpcHttpServiceTest {
final RequestBody body =
RequestBody.create(
JSON, "{\"jsonrpc\":\"2.0\",\"id\":{},\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
final JsonObject json = new JsonObject(resp.body().string());
final JsonRpcError expectedError = JsonRpcError.INVALID_REQUEST;
@ -1376,9 +1328,8 @@ public class JsonRpcHttpServiceTest {
final RequestBody body =
RequestBody.create(
JSON, "{\"jsonrpc\":\"2.0\",\"id\":[],\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
final JsonObject json = new JsonObject(resp.body().string());
final JsonRpcError expectedError = JsonRpcError.INVALID_REQUEST;
@ -1392,9 +1343,8 @@ public class JsonRpcHttpServiceTest {
final Integer id = 2;
final RequestBody body =
RequestBody.create(JSON, "{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + "}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
final JsonObject json = new JsonObject(resp.body().string());
final JsonRpcError expectedError = JsonRpcError.INVALID_REQUEST;
@ -1406,9 +1356,8 @@ public class JsonRpcHttpServiceTest {
@Test
public void invalidJson() throws Exception {
final RequestBody body = RequestBody.create(JSON, "{bla");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
final JsonObject json = new JsonObject(resp.body().string());
final JsonRpcError expectedError = JsonRpcError.PARSE_ERROR;
@ -1420,9 +1369,8 @@ public class JsonRpcHttpServiceTest {
@Test
public void wrongJsonType() throws Exception {
final RequestBody body = RequestBody.create(JSON, "\"a string\"");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
final JsonObject json = new JsonObject(resp.body().string());
final JsonRpcError expectedError = JsonRpcError.PARSE_ERROR;
@ -1440,9 +1388,8 @@ public class JsonRpcHttpServiceTest {
"{\"jsonrpc\":\"1.0\",\"id\":"
+ Json.encode(id)
+ ",\"method\":\"web3_clientVersion\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
final JsonObject json = new JsonObject(resp.body().string());
testHelper.assertValidJsonRpcResult(json, id);
@ -1457,9 +1404,8 @@ public class JsonRpcHttpServiceTest {
final RequestBody body =
RequestBody.create(
JSON, "{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"bla\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
final JsonObject json = new JsonObject(resp.body().string());
final JsonRpcError expectedError = JsonRpcError.METHOD_NOT_FOUND;
@ -1479,9 +1425,8 @@ public class JsonRpcHttpServiceTest {
final RequestBody body =
RequestBody.create(JSON, "{\"jsonrpc\":\"2.0\",\"id\":\"666\",\"method\":\"foo\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(500);
}
}
@ -1500,9 +1445,8 @@ public class JsonRpcHttpServiceTest {
"[{\"jsonrpc\":\"2.0\",\"id\":\"000\",\"method\":\"web3_clientVersion\"},"
+ "{\"jsonrpc\":\"2.0\",\"id\":\"111\",\"method\":\"foo\"},"
+ "{\"jsonrpc\":\"2.0\",\"id\":\"222\",\"method\":\"net_version\"}]");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(500);
}
}
@ -1524,9 +1468,8 @@ public class JsonRpcHttpServiceTest {
+ "{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(netVersionRequestId)
+ ",\"method\":\"net_version\"}]");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonArray json = new JsonArray(resp.body().string());
@ -1573,9 +1516,8 @@ public class JsonRpcHttpServiceTest {
+ ",\"method\":\"net_version\"}";
final String batchRequest = "[" + String.join(", ", reqs) + "]";
final RequestBody body = RequestBody.create(JSON, batchRequest);
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String jsonStr = resp.body().string();
@ -1621,9 +1563,8 @@ public class JsonRpcHttpServiceTest {
+ "]";
final RequestBody body = RequestBody.create(JSON, req);
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
final JsonObject json = new JsonObject(resp.body().string());
final JsonRpcError expectedError = JsonRpcError.PARSE_ERROR;
@ -1646,9 +1587,8 @@ public class JsonRpcHttpServiceTest {
+ "{\"jsonrpc\":\"2.0\",\"id\":"
+ Json.encode(netVersionRequestId)
+ ",\"method\":\"net_version\"}]");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final JsonArray json = new JsonArray(resp.body().string());
@ -1680,9 +1620,8 @@ public class JsonRpcHttpServiceTest {
@Test
public void emptyBatchRequest() throws Exception {
final RequestBody body = RequestBody.create(JSON, "[]");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
final JsonObject json = new JsonObject(resp.body().string());
final JsonRpcError expectedError = JsonRpcError.INVALID_REQUEST;
@ -1812,10 +1751,9 @@ public class JsonRpcHttpServiceTest {
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"eth_syncing\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
when(synchronizer.getSyncStatus()).thenReturn(Optional.empty());
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Verify general result format.
final JsonObject json = new JsonObject(resp.body().string());
@ -1834,9 +1772,8 @@ public class JsonRpcHttpServiceTest {
RequestBody.create(
JSON,
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"eth_syncing\"}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
final String respBody = resp.body().string();
final JsonObject json = new JsonObject(respBody);
final JsonObject result = json.getJsonObject("result");
@ -1902,9 +1839,8 @@ public class JsonRpcHttpServiceTest {
+ "\",\""
+ UInt256.ZERO
+ "\",\"latest\"]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -1938,9 +1874,8 @@ public class JsonRpcHttpServiceTest {
+ "\",\""
+ UInt256.ONE
+ "\",\"latest\"]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -1973,9 +1908,8 @@ public class JsonRpcHttpServiceTest {
+ "\",\""
+ UInt256.ONE
+ "\",\"earliest\"]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -2010,9 +1944,8 @@ public class JsonRpcHttpServiceTest {
+ "\",\""
+ 0L
+ "\"]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(200);
// Check general format of result
final String respBody = resp.body().string();
@ -2043,9 +1976,8 @@ public class JsonRpcHttpServiceTest {
+ "\",\""
+ "blah"
+ "\",\"latest\"]}");
final Request request = new Request.Builder().post(body).url(baseUrl).build();
try (final Response resp = client.newCall(request).execute()) {
try (final Response resp = client.newCall(buildPostRequest(body)).execute()) {
assertThat(resp.code()).isEqualTo(400);
// Check general format of result
final JsonObject json = new JsonObject(resp.body().string());
@ -2054,4 +1986,12 @@ public class JsonRpcHttpServiceTest {
json, id, expectedError.getCode(), expectedError.getMessage());
}
}
private Request buildPostRequest(final RequestBody body) {
return new Request.Builder().post(body).url(baseUrl).build();
}
private Request buildGetRequest(final String path) {
return new Request.Builder().get().url(baseUrl + path).build();
}
}

@ -19,6 +19,7 @@ import static tech.pegasys.pantheon.cli.DefaultCommandValues.getDefaultPantheonD
import tech.pegasys.pantheon.Runner;
import tech.pegasys.pantheon.RunnerBuilder;
import tech.pegasys.pantheon.cli.custom.CorsAllowedOriginsProperty;
import tech.pegasys.pantheon.cli.custom.JsonRPCWhitelistHostsProperty;
import tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueRpcApis;
import tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftRpcApis;
import tech.pegasys.pantheon.controller.KeyPairUtil;
@ -311,6 +312,16 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
)
private final Collection<RpcApi> wsApis = null;
@Option(
names = {"--host-whitelist"},
paramLabel = "<hostname>",
description =
"Comma separated list of hostnames to whitelist for RPC access. default: ${DEFAULT-VALUE}",
defaultValue = "localhost",
converter = JsonRPCWhitelistHostsProperty.JsonRPCWhitelistHostsConverter.class
)
private final JsonRPCWhitelistHostsProperty hostsWhitelist = new JsonRPCWhitelistHostsProperty();
@Option(
names = {"--dev-mode"},
description =
@ -483,6 +494,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
jsonRpcConfiguration.setPort(rpcHostAndPort.getPort());
jsonRpcConfiguration.setCorsAllowedDomains(rpcCorsAllowedOrigins.getDomains());
jsonRpcConfiguration.setRpcApis(rpcApis);
jsonRpcConfiguration.setHostsWhitelist(hostsWhitelist.hostnamesWhitelist());
return jsonRpcConfiguration;
}

@ -0,0 +1,70 @@
/*
* Copyright 2018 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.
*/
package tech.pegasys.pantheon.cli.custom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import picocli.CommandLine;
public class JsonRPCWhitelistHostsProperty {
private List<String> hostnamesWhitelist = Collections.emptyList();
private JsonRPCWhitelistHostsProperty(final List<String> hostnamesWhitelist) {
this.hostnamesWhitelist = hostnamesWhitelist;
}
public JsonRPCWhitelistHostsProperty() {}
public List<String> hostnamesWhitelist() {
return hostnamesWhitelist;
}
public static class JsonRPCWhitelistHostsConverter
implements CommandLine.ITypeConverter<JsonRPCWhitelistHostsProperty> {
@Override
public JsonRPCWhitelistHostsProperty convert(final String value) {
final List<String> hostNames;
if (value != null && !value.isEmpty()) {
hostNames = new ArrayList<>(Arrays.asList(value.split("\\s*,\\s*")));
} else {
throw new IllegalArgumentException("Property can't be null/empty string");
}
if (hostNames.contains("all")) {
if (hostNames.size() > 1) {
throw new IllegalArgumentException("Value 'all' can't be used with other hostnames");
} else {
return new JsonRPCWhitelistHostsProperty(Collections.singletonList("*"));
}
}
if (hostNames.contains("*")) {
if (hostNames.size() > 1) {
throw new IllegalArgumentException("Value '*' can't be used with other hostnames");
} else {
return new JsonRPCWhitelistHostsProperty(Collections.singletonList("*"));
}
}
if (hostNames.size() > 0) {
return new JsonRPCWhitelistHostsProperty(hostNames);
} else {
return new JsonRPCWhitelistHostsProperty();
}
}
}
}

@ -252,6 +252,7 @@ public final class RunnerTest {
final JsonRpcConfiguration configuration = JsonRpcConfiguration.createDefault();
configuration.setPort(0);
configuration.setEnabled(true);
configuration.setHostsWhitelist(Collections.singletonList("*"));
return configuration;
}
@ -263,8 +264,7 @@ public final class RunnerTest {
}
private PermissioningConfiguration permissioningConfiguration() {
final PermissioningConfiguration configuration = PermissioningConfiguration.createDefault();
return configuration;
return PermissioningConfiguration.createDefault();
}
private static void setupState(

@ -707,6 +707,62 @@ public class PantheonCommandTest extends CommandTestAbstract {
.contains("Domain values result in invalid regex pattern");
}
@Test
public void jsonRpcHostWhitelistAcceptsSingleArgument() {
parseCommand("--host-whitelist", "a");
verify(mockRunnerBuilder).jsonRpcConfiguration(jsonRpcConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsWhitelist().size()).isEqualTo(1);
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsWhitelist()).contains("a");
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsWhitelist())
.doesNotContain("localhost");
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString()).isEmpty();
}
@Test
public void jsonRpcHostWhitelistAcceptsMultipleArguments() {
parseCommand("--host-whitelist", "a,b");
verify(mockRunnerBuilder).jsonRpcConfiguration(jsonRpcConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsWhitelist().size()).isEqualTo(2);
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsWhitelist()).contains("a", "b");
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsWhitelist())
.doesNotContain("*", "localhost");
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString()).isEmpty();
}
@Test
public void jsonRpcHostWhitelistStarWithAnotherHostnameMustFail() {
final String[] origins = {"friend", "*"};
parseCommand("--host-whitelist", String.join(",", origins));
verifyZeroInteractions(mockRunnerBuilder);
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString())
.contains("Value '*' can't be used with other hostnames");
}
@Test
public void jsonRpcHostWhitelistAllWithAnotherHostnameMustFail() {
final String[] origins = {"friend", "all"};
parseCommand("--host-whitelist", String.join(",", origins));
verifyZeroInteractions(mockRunnerBuilder);
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString())
.contains("Value 'all' can't be used with other hostnames");
}
@Test
public void wsRpcEnabledPropertyDefaultIsFalse() {
parseCommand();

@ -57,6 +57,7 @@ public class DockerQuickstartTest {
private static final String DEFAULT_RPC_HOST =
Optional.ofNullable(System.getenv("DOCKER_PORT_2375_TCP_ADDR")).orElse("localhost");
private static final String DEFAULT_HTTP_RPC_HOST = "http://" + DEFAULT_RPC_HOST;
private static final String DEFAULT_HOST_HEADER = "localhost";
private final Map<ServicesIdentifier, Service> services = new EnumMap<>(ServicesIdentifier.class);
private final Map<EndpointsIdentifier, String> endpoints =
new EnumMap<>(EndpointsIdentifier.class);
@ -104,8 +105,7 @@ public class DockerQuickstartTest {
assertThat(services).isNotNull().isNotEmpty();
assertThat(endpoints).isNotNull().isNotEmpty();
web3HttpClient =
Web3j.build(
HttpService httpService =
new HttpService(
DEFAULT_HTTP_RPC_HOST
+ ":"
@ -113,10 +113,9 @@ public class DockerQuickstartTest {
.get(ServicesIdentifier.RPCNODE)
.exposedPorts
.get(DEFAULT_HTTP_RPC_PORT)
.externalPort),
2000,
Async.defaultExecutorService());
.externalPort);
httpService.addHeader("Host", DEFAULT_HOST_HEADER);
web3HttpClient = Web3j.build(httpService, 2000, Async.defaultExecutorService());
assertThat(web3HttpClient).isNotNull();
}

Loading…
Cancel
Save