Skip to content

Commit

Permalink
[NC-2044] jsonrpc authentication cli options & acceptance tests (Pega…
Browse files Browse the repository at this point in the history
  • Loading branch information
Errorific authored Feb 8, 2019
1 parent cd02b4d commit 6015643
Show file tree
Hide file tree
Showing 19 changed files with 438 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Clique;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Eth;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Ibft;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Login;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Net;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Perm;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Web3;
Expand Down Expand Up @@ -46,6 +47,7 @@ public class AcceptanceTestBase {
protected final Ibft ibft;
protected final Web3 web3;
protected final Eth eth;
protected final Login login;
protected final Net net;
protected final Perm perm;
protected final Admin admin;
Expand All @@ -63,6 +65,7 @@ protected AcceptanceTestBase() {

clique = new Clique(ethTransactions, cliqueTransactions);
ibft = new Ibft(ibftTransactions);
login = new Login();
net = new Net(new NetTransactions());
cluster = new Cluster(net);
transactions = new Transactions(accounts);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2019 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.tests.acceptance.dsl.httptransaction;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;

import io.vertx.core.json.JsonObject;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class HttpRequestFactory {
private final String uri;
private final OkHttpClient client;
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

public HttpRequestFactory(final String uri) {
this.uri = uri;
client = new OkHttpClient();
}

public JsonObject loginSuccessful(final String username, final String password)
throws IOException {
final RequestBody requestBody =
RequestBody.create(
JSON, "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}");
final Request request = new Request.Builder().post(requestBody).url(uri + "/login").build();
try (final Response response = client.newCall(request).execute()) {

assertThat(response.code()).isEqualTo(200);
assertThat(response.message()).isEqualTo("OK");
final ResponseBody responseBody = response.body();
assertThat(responseBody.contentType()).isNotNull();
assertThat(responseBody.contentType().type()).isEqualTo("application");
assertThat(responseBody.contentType().subtype()).isEqualTo("json");
final String bodyString = responseBody.string();
assertThat(bodyString).isNotNull();
assertThat(bodyString).isNotBlank();

return new JsonObject(bodyString);
}
}

public void loginUnauthorized(final String username, final String password) throws IOException {
final RequestBody requestBody =
RequestBody.create(
JSON, "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}");
final Request request = new Request.Builder().post(requestBody).url(uri + "/login").build();
try (final Response response = client.newCall(request).execute()) {
assertThat(response.code()).isEqualTo(401);
assertThat(response.message()).isEqualTo("Unauthorized");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2019 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.tests.acceptance.dsl.httptransaction;

@FunctionalInterface
public interface HttpTransaction<T> {

T execute(final HttpRequestFactory httpFactory);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2019 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.tests.acceptance.dsl.httptransaction;

import static org.junit.Assert.fail;

import java.io.IOException;

import io.vertx.core.json.JsonObject;

public class LoginTransaction implements HttpTransaction<String> {
private final String username;
private final String password;

public LoginTransaction(final String username, final String password) {
this.username = username;
this.password = password;
}

@Override
public String execute(final HttpRequestFactory httpFactory) {
try {
final JsonObject response = httpFactory.loginSuccessful(username, password);
final String token = response.getString("token");
return token;
} catch (IOException e) {
fail("Login request failed with exception: " + e.toString());
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2019 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.tests.acceptance.dsl.httptransaction;

import static org.junit.Assert.fail;

import java.io.IOException;

public class LoginUnauthorizedTransaction implements HttpTransaction<Void> {
private final String username;
private final String password;

public LoginUnauthorizedTransaction(final String username, final String password) {
this.username = username;
this.password = password;
}

@Override
public Void execute(final HttpRequestFactory httpFactory) {
try {
httpFactory.loginUnauthorized(username, password);
return null;
} catch (IOException e) {
fail("Login request failed with exception: " + e.toString());
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2019 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.tests.acceptance.dsl.jsonrpc;

import static org.assertj.core.api.Assertions.assertThat;

import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition;
import tech.pegasys.pantheon.tests.acceptance.dsl.httptransaction.LoginTransaction;
import tech.pegasys.pantheon.tests.acceptance.dsl.httptransaction.LoginUnauthorizedTransaction;

public class Login {

public Condition loginSucceeds(final String username, final String password) {
return (n) -> {
final String token = n.executeHttpTransaction(new LoginTransaction(username, password));
assertThat(token).isNotBlank();
};
}

public Condition loginFails(final String username, final String password) {
return (n) -> {
n.executeHttpTransaction(new LoginUnauthorizedTransaction(username, password));
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
package tech.pegasys.pantheon.tests.acceptance.dsl.node;

import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition;
import tech.pegasys.pantheon.tests.acceptance.dsl.httptransaction.HttpTransaction;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction;
import tech.pegasys.pantheon.tests.acceptance.dsl.waitcondition.WaitCondition;

public interface Node {
<T> T execute(Transaction<T> transaction);

<T> T executeHttpTransaction(HttpTransaction<T> transaction);

void verify(final Condition expected);

void waitUntil(final WaitCondition condition);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition;
import tech.pegasys.pantheon.tests.acceptance.dsl.httptransaction.HttpRequestFactory;
import tech.pegasys.pantheon.tests.acceptance.dsl.httptransaction.HttpTransaction;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.AdminJsonRpcRequestFactory;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.CliqueJsonRpcRequestFactory;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.IbftJsonRpcRequestFactory;
Expand Down Expand Up @@ -85,6 +87,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto

private List<String> bootnodes = new ArrayList<>();
private JsonRequestFactories jsonRequestFactories;
private HttpRequestFactory httpRequestFactory;
private Optional<EthNetworkConfig> ethNetworkConfig = Optional.empty();

public PantheonNode(
Expand Down Expand Up @@ -188,6 +191,14 @@ private JsonRequestFactories jsonRequestFactories() {
return jsonRequestFactories;
}

private HttpRequestFactory httpRequestFactory() {
if (httpRequestFactory == null) {
httpRequestFactory =
new HttpRequestFactory(jsonRpcBaseUrl().orElse("http://" + LOCALHOST + ":8545"));
}
return httpRequestFactory;
}

/** All future JSON-RPC calls are made via a web sockets connection. */
@Override
public void useWebSocketsForJsonRpc() {
Expand Down Expand Up @@ -401,6 +412,11 @@ public <T> T execute(final Transaction<T> transaction) {
return transaction.execute(jsonRequestFactories());
}

@Override
public <T> T executeHttpTransaction(final HttpTransaction<T> transaction) {
return transaction.execute(httpRequestFactory());
}

@Override
public void verify(final Condition expected) {
expected.verify(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ public void startNode(final PantheonNode node) {
params.add(node.jsonRpcListenAddress().get());
params.add("--rpc-api");
params.add(apiList(node.jsonRpcConfiguration().getRpcApis()));
if (node.jsonRpcConfiguration().isAuthenticationEnabled()) {
params.add("--rpc-http-authentication-enabled");
}
if (node.jsonRpcConfiguration().getAuthenticationCredentialsFile() != null) {
params.add("--rpc-http-authentication-credentials-file");
params.add(node.jsonRpcConfiguration().getAuthenticationCredentialsFile());
}
}

if (node.wsRpcEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.GenesisConfigProvider;

import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.Optional;

public class PantheonFactoryConfigurationBuilder {
Expand Down Expand Up @@ -61,12 +63,23 @@ public PantheonFactoryConfigurationBuilder setJsonRpcConfiguration(
}

public PantheonFactoryConfigurationBuilder jsonRpcEnabled() {
final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault();
config.setEnabled(true);
config.setPort(0);
config.setHostsWhitelist(singletonList("*"));
this.jsonRpcConfiguration.setEnabled(true);
this.jsonRpcConfiguration.setPort(0);
this.jsonRpcConfiguration.setHostsWhitelist(singletonList("*"));

return this;
}

public PantheonFactoryConfigurationBuilder jsonRpcAuthenticationEnabled()
throws URISyntaxException {
final String authTomlPath =
Paths.get(ClassLoader.getSystemResource("authentication/auth.toml").toURI())
.toAbsolutePath()
.toString();

this.jsonRpcConfiguration.setAuthenticationEnabled(true);
this.jsonRpcConfiguration.setAuthenticationCredentialsFile(authTomlPath);

this.jsonRpcConfiguration = config;
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@ public PantheonNode createArchiveNodeWithDiscoveryDisabledAndAdmin(final String
.build());
}

public PantheonNode createArchiveNodeWithAuthentication(final String name)
throws IOException, URISyntaxException {
return create(
new PantheonFactoryConfigurationBuilder()
.setName(name)
.jsonRpcEnabled()
.jsonRpcAuthenticationEnabled()
.webSocketEnabled()
.build());
}

public PantheonNode createNodeWithP2pDisabled(final String name) throws IOException {
return create(
new PantheonFactoryConfigurationBuilder()
Expand Down
Loading

0 comments on commit 6015643

Please sign in to comment.