Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow use a external JWT public key in authenticated APIs #183

Merged
merged 42 commits into from
Nov 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
d333278
allow verification of externally signed jwt
jframe Nov 8, 2019
943f0d1
move jwt configuration out of the auth service so it can be tested
jframe Nov 8, 2019
4543681
jwt auth options ut
jframe Nov 11, 2019
778a6c5
add file headers
jframe Nov 11, 2019
22066b6
increase generated key size to 2048 as recommended in the jwt rfc whe…
jframe Nov 11, 2019
a55d2ea
disable login if external jwt public key is used
jframe Nov 11, 2019
c0e7c20
Merge branch 'master' into external_jwt
jframe Nov 11, 2019
5708c08
handle JWT auth without credentials file
jframe Nov 12, 2019
a55558c
Only allow Auth service to be enabled if auth is enabled. Fixes the ATs
jframe Nov 12, 2019
9d24f8d
http rpc JWT external public key ATs
jframe Nov 12, 2019
44874a0
ws rpc JWT external public key ATs
jframe Nov 12, 2019
1d770b7
refactor login ATs
jframe Nov 12, 2019
4c3b89a
spotless
jframe Nov 12, 2019
c769ac3
Fix compile error
jframe Nov 12, 2019
0800233
final
jframe Nov 12, 2019
77f749f
change besu CLI so that ws can handle JWT auth without credentials file
jframe Nov 12, 2019
6b9b80f
revert unneeded change
jframe Nov 12, 2019
d27c814
update command line help
jframe Nov 12, 2019
b27f140
additional besu command uts
jframe Nov 13, 2019
4e221aa
PR changes: rename AT var
jframe Nov 13, 2019
c47b0a7
Fail JWT if expiry claim doesn't exist
jframe Nov 14, 2019
a18ccb8
use pem file format
jframe Nov 14, 2019
4b287d9
handle invalid pem file format
jframe Nov 14, 2019
7584013
update cli description to mention file is in pem format
jframe Nov 14, 2019
014d2fe
spotless
jframe Nov 14, 2019
88631ad
additional unit tests
jframe Nov 14, 2019
bf29286
default charset warning
jframe Nov 14, 2019
e1dc25a
Merge branch 'master' into external_jwt
jframe Nov 14, 2019
3e4dd66
PR changes: simplify AT authenticated node creation
jframe Nov 14, 2019
7e4351a
PR changes: split failure AT tests out into separate tests
jframe Nov 14, 2019
5e1d9ed
Merge branch 'external_jwt' of github.com:jframe/besu into external_jwt
jframe Nov 14, 2019
e13b9db
fix closing of pem reading file stream
jframe Nov 14, 2019
c4caf32
fix closing of pem reading file stream
jframe Nov 15, 2019
e3154f1
finals
jframe Nov 15, 2019
0b98878
PR changes for http login AT
jframe Nov 15, 2019
eef9610
PR changes for ws login AT
jframe Nov 15, 2019
6eab286
compile error
jframe Nov 15, 2019
80deef5
add jwt into the cli options
jframe Nov 15, 2019
f3aaf7d
remove unnecessary capitalisation in cli description
jframe Nov 15, 2019
19fedcf
spotless
jframe Nov 15, 2019
08fb77b
update the cli options when using process runner in ATs
jframe Nov 15, 2019
a51d52f
Merge branch 'master' into external_jwt
jframe Nov 17, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,16 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.acceptance.dsl.condition.net;
package org.hyperledger.besu.tests.acceptance.dsl.condition.login;

import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.net.NetVersionTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.login.LoginDisabledTransaction;

public class ExpectNetVersionPermissionJsonRpcUnauthorizedResponse implements Condition {

private final NetVersionTransaction transaction;

public ExpectNetVersionPermissionJsonRpcUnauthorizedResponse(
final NetVersionTransaction transaction) {
this.transaction = transaction;
}
public class ExpectLoginDisabled implements Condition {

@Override
public void verify(final Node node) {
node.execute(transaction);
node.execute(new LoginDisabledTransaction());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public Condition failure(final String username, final String password) {
return new ExpectLoginUnauthorized(username, password);
}

public Condition disabled() {
return new ExpectLoginDisabled();
}

public Condition awaitResponse(final String username, final String password) {
return new AwaitLoginResponse<>(new LoginTransaction(username, password));
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,20 @@

import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.net.NetVersionTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;

public class ExpectNetVersionConnectionExceptionWithCause implements Condition {
public class ExpectUnauthorized implements Condition {

private final NetVersionTransaction transaction;
private final Class<? extends Throwable> cause;
private static final String UNAUTHORIZED = "Unauthorized";
private final Transaction<?> transaction;

public ExpectNetVersionConnectionExceptionWithCause(
final NetVersionTransaction transaction, final Class<? extends Throwable> cause) {
public ExpectUnauthorized(final Transaction<?> transaction) {
this.transaction = transaction;
this.cause = cause;
}

@Override
public void verify(final Node node) {
final Throwable thrown = catchThrowable(() -> node.execute(transaction));
assertThat(thrown).isInstanceOf(cause);
assertThat(thrown.getMessage()).contains(UNAUTHORIZED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public Condition netServicesOnlyJsonRpcEnabled() {
return new ExpectNetServicesReturnsOnlyJsonRpcActive(transactions.netServices());
}

public Condition netServicesUnauthorized() {
return new ExpectUnauthorized(transactions.netServices());
}

public Condition netVersion() {
return new ExpectNetVersionIsNotBlank(transactions.netVersion());
}
Expand All @@ -47,16 +51,8 @@ public Condition netVersionExceptional(final String expectedMessage) {
return new ExpectNetVersionConnectionException(transactions.netVersion(), expectedMessage);
}

public Condition netVersionExceptional(final Class<? extends Throwable> cause) {
return new ExpectNetVersionConnectionExceptionWithCause(transactions.netVersion(), cause);
}

public Condition netVersionUnauthorizedExceptional(final String expectedMessage) {
return new ExpectNetVersionPermissionException(transactions.netVersion(), expectedMessage);
}

public Condition netVersionUnauthorizedResponse() {
return new ExpectNetVersionPermissionJsonRpcUnauthorizedResponse(transactions.netVersion());
public Condition netVersionUnauthorized() {
return new ExpectUnauthorized(transactions.netVersion());
}

public Condition awaitPeerCountExceptional() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ public void startNode(final BesuNode node) {
params.add("--rpc-http-authentication-credentials-file");
params.add(node.jsonRpcConfiguration().getAuthenticationCredentialsFile());
}
if (node.jsonRpcConfiguration().getAuthenticationPublicKeyFile() != null) {
jframe marked this conversation as resolved.
Show resolved Hide resolved
params.add("--rpc-http-authentication-jwt-public-key-file");
params.add(node.jsonRpcConfiguration().getAuthenticationPublicKeyFile().getAbsolutePath());
}
}

if (node.wsRpcEnabled()) {
Expand All @@ -149,6 +153,11 @@ public void startNode(final BesuNode node) {
params.add("--rpc-ws-authentication-credentials-file");
params.add(node.webSocketConfiguration().getAuthenticationCredentialsFile());
}
if (node.webSocketConfiguration().getAuthenticationPublicKeyFile() != null) {
params.add("--rpc-ws-authentication-jwt-public-key-file");
params.add(
node.webSocketConfiguration().getAuthenticationPublicKeyFile().getAbsolutePath());
}
}

if (node.isMetricsEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationProvider;

import java.io.File;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.ArrayList;
Expand Down Expand Up @@ -114,6 +115,19 @@ public BesuNodeConfigurationBuilder jsonRpcAuthenticationEnabled() throws URISyn
return this;
}

public BesuNodeConfigurationBuilder jsonRpcAuthenticationUsingPublicKeyEnabled()
throws URISyntaxException {
final File jwtPublicKey =
Paths.get(ClassLoader.getSystemResource("authentication/jwt_public_key").toURI())
.toAbsolutePath()
.toFile();

this.jsonRpcConfiguration.setAuthenticationEnabled(true);
this.jsonRpcConfiguration.setAuthenticationPublicKeyFile(jwtPublicKey);

return this;
}

public BesuNodeConfigurationBuilder webSocketConfiguration(
final WebSocketConfiguration webSocketConfiguration) {
this.webSocketConfiguration = webSocketConfiguration;
Expand All @@ -130,7 +144,7 @@ public BesuNodeConfigurationBuilder webSocketEnabled() {
final WebSocketConfiguration config = WebSocketConfiguration.createDefault();
config.setEnabled(true);
config.setPort(0);
config.setHostsWhitelist(Collections.singleton("*"));
config.setHostsWhitelist(Collections.singletonList("*"));

this.webSocketConfiguration = config;
return this;
Expand All @@ -153,6 +167,19 @@ public BesuNodeConfigurationBuilder webSocketAuthenticationEnabled() throws URIS
return this;
}

public BesuNodeConfigurationBuilder webSocketAuthenticationUsingPublicKeyEnabled()
throws URISyntaxException {
final File jwtPublicKey =
Paths.get(ClassLoader.getSystemResource("authentication/jwt_public_key").toURI())
.toAbsolutePath()
.toFile();

this.webSocketConfiguration.setAuthenticationEnabled(true);
this.webSocketConfiguration.setAuthenticationPublicKeyFile(jwtPublicKey);

return this;
}

public BesuNodeConfigurationBuilder permissioningConfiguration(
final PermissioningConfiguration permissioningConfiguration) {
this.permissioningConfiguration = Optional.of(permissioningConfiguration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,24 +128,27 @@ public BesuNode createArchiveNodeNetServicesDisabled(final String name) throws I
.build());
}

public BesuNode createArchiveNodeWithAuthentication(final String name)
public BesuNode createNodeWithAuthentication(final String name)
throws IOException, URISyntaxException {
return create(
new BesuNodeConfigurationBuilder()
.name(name)
.jsonRpcEnabled()
.jsonRpcAuthenticationEnabled()
.webSocketEnabled()
.webSocketAuthenticationEnabled()
.build());
}

public BesuNode createArchiveNodeWithAuthenticationOverWebSocket(final String name)
public BesuNode createNodeWithAuthenticationUsingJwtPublicKey(final String name)
throws IOException, URISyntaxException {
return create(
new BesuNodeConfigurationBuilder()
.name(name)
.jsonRpcEnabled()
.jsonRpcAuthenticationUsingPublicKeyEnabled()
.webSocketEnabled()
.webSocketAuthenticationEnabled()
.webSocketAuthenticationUsingPublicKeyEnabled()
.build());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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.besu.tests.acceptance.dsl.transaction.login;

import static org.assertj.core.api.Fail.fail;

import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;

import java.io.IOException;

import org.assertj.core.api.Assertions;

public class LoginDisabledTransaction implements Transaction<Void> {

@Override
public Void execute(final NodeRequests node) {
try {
final String loginResponse = node.login().send("user", "password");
Assertions.assertThat(loginResponse).isEqualTo("Authentication not enabled");
return null;
} catch (final IOException e) {
fail("Login request failed with exception: ", e);
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public Map<String, Map<String, String>> execute(final NodeRequests requestFactor
} catch (final Exception e) {
throw new RuntimeException(e);
}
if (netServicesResponse.hasError()) {
throw new RuntimeException(netServicesResponse.getError().getMessage());
}
return netServicesResponse.getResult();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public String execute(final NodeRequests node) {
try {
final NetVersion result = node.net().netVersion().send();
assertThat(result).isNotNull();
if (result.hasError()) {
throw new RuntimeException(result.getError().getMessage());
}
return result.getNetVersion();
} catch (final Exception e) {
throw new RuntimeException(e);
Expand Down
Loading