Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

PAN-2860: Ignore discport during startup whitelist validation #1625

Merged
merged 3 commits into from
Jul 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -41,11 +41,15 @@ public NodePermissioningController(
}

public boolean isPermitted(final EnodeURL sourceEnode, final EnodeURL destinationEnode) {
LOG.trace("Checking node permission: {} -> {}", sourceEnode, destinationEnode);
LOG.trace("Node permissioning: Checking {} -> {}", sourceEnode, destinationEnode);

if (syncStatusNodePermissioningProvider
.map(p -> !p.hasReachedSync() && p.isPermitted(sourceEnode, destinationEnode))
.orElse(false)) {

LOG.trace(
"Node permissioning - Sync Status: Permitted {} -> {}", sourceEnode, destinationEnode);

return true;
}

Expand All @@ -54,19 +58,40 @@ public boolean isPermitted(final EnodeURL sourceEnode, final EnodeURL destinatio
p -> p.isPermitted(sourceEnode, destinationEnode));

if (insufficientPeerPermission.isPresent()) {
return insufficientPeerPermission.get();
final Boolean permitted = insufficientPeerPermission.get();

LOG.trace(
"Node permissioning - Insufficient Peers: {} {} -> {}",
permitted ? "Permitted" : "Rejected",
sourceEnode,
destinationEnode);

return permitted;
}

if (syncStatusNodePermissioningProvider.isPresent()
&& !syncStatusNodePermissioningProvider.get().isPermitted(sourceEnode, destinationEnode)) {

LOG.trace(
"Node permissioning - Sync Status: Rejected {} -> {}", sourceEnode, destinationEnode);

return false;
} else {
for (final NodePermissioningProvider provider : providers) {
if (!provider.isPermitted(sourceEnode, destinationEnode)) {
LOG.trace(
"Node permissioning - {}: Rejected {} -> {}",
provider.getClass().getSimpleName(),
sourceEnode,
destinationEnode);

return false;
}
}
}

LOG.trace("Node permissioning: Permitted {} -> {}", sourceEnode, destinationEnode);

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public boolean isPermitted(final EnodeURL sourceEnode, final EnodeURL destinatio
return true;
} else {
checkCounter.inc();
if (fixedNodes.contains(destinationEnode)) {
if (fixedNodes.stream().anyMatch(p -> EnodeURL.sameListeningEndpoint(p, destinationEnode))) {
checkCounterPermitted.inc();
return true;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.Collection;
import java.util.function.IntSupplier;

import com.google.common.collect.Lists;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -187,4 +188,25 @@ public void whenHasSyncedIsPermittedShouldReturnTrue() {
verify(checkPermittedCounter, times(0)).inc();
verify(checkUnpermittedCounter, times(0)).inc();
}

@Test
public void syncStatusPermissioningCheckShouldIgnoreEnodeURLDiscoveryPort() {
syncStatusListener.onSyncStatus(new SyncStatus(0, 1, 2));
assertThat(provider.hasReachedSync()).isFalse();

final EnodeURL bootnode =
EnodeURL.fromString(
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.3:5678");
final EnodeURL enodeWithDiscoveryPort =
EnodeURL.fromString(
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.3:5678?discport=30303");

final SyncStatusNodePermissioningProvider provider =
new SyncStatusNodePermissioningProvider(
synchronizer, Lists.newArrayList(bootnode), metricsSystem);

boolean isPermitted = provider.isPermitted(enode1, enodeWithDiscoveryPort);

assertThat(isPermitted).isTrue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import tech.pegasys.pantheon.ethereum.permissioning.LocalPermissioningConfiguration;

import java.net.URI;
import java.util.ArrayList;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -26,16 +26,38 @@ public static void areAllNodesAreInWhitelist(
final Collection<URI> nodeURIs,
final LocalPermissioningConfiguration permissioningConfiguration)
throws Exception {
List<URI> nodesNotInWhitelist = new ArrayList<>();

if (permissioningConfiguration.isNodeWhitelistEnabled() && nodeURIs != null) {
nodesNotInWhitelist =
final List<URI> whitelistNodesWithoutQueryParam =
permissioningConfiguration.getNodeWhitelist().stream()
.map(PermissioningConfigurationValidator::removeQueryFromURI)
.collect(Collectors.toList());

final List<URI> nodeURIsNotInWhitelist =
nodeURIs.stream()
.filter(enode -> !permissioningConfiguration.getNodeWhitelist().contains(enode))
.map(PermissioningConfigurationValidator::removeQueryFromURI)
.filter(uri -> !whitelistNodesWithoutQueryParam.contains(uri))
.collect(Collectors.toList());

if (!nodeURIsNotInWhitelist.isEmpty()) {
throw new Exception(
"Specified node(s) not in nodes-whitelist " + enodesAsStrings(nodeURIsNotInWhitelist));
}
}
if (!nodesNotInWhitelist.isEmpty()) {
throw new Exception(
"Specified node(s) not in nodes-whitelist " + enodesAsStrings(nodesNotInWhitelist));
}

private static URI removeQueryFromURI(final URI uri) {
try {
return new URI(
uri.getScheme(),
uri.getUserInfo(),
uri.getHost(),
uri.getPort(),
uri.getPath(),
null,
uri.getFragment());
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.List;
import java.util.stream.Collectors;

import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import org.junit.Test;

Expand Down Expand Up @@ -89,4 +90,35 @@ public void nodesWhitelistOptionWhichDoesNotIncludeBootnodesMustError() throws E
"enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303");
}
}

@Test
public void nodeWhitelistCheckShouldIgnoreDiscoveryPortParam() throws Exception {
final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG);
final Path toml = Files.createTempFile("toml", "");
toml.toFile().deleteOnExit();
Files.write(toml, Resources.toByteArray(configFile));

final LocalPermissioningConfiguration permissioningConfiguration =
PermissioningConfigurationBuilder.permissioningConfiguration(
true, toml.toAbsolutePath().toString(), true, toml.toAbsolutePath().toString());

// This node is defined in the PERMISSIONING_CONFIG file without the discovery port
final URI enodeURL =
URI.create(
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.9:4567?discport=30303");

// In an URI comparison the URLs should not match
boolean isInWhitelist = permissioningConfiguration.getNodeWhitelist().contains(enodeURL);
assertThat(isInWhitelist).isFalse();

// However, for the whitelist validation, we should ignore the discovery port and don't throw an
// error
try {
PermissioningConfigurationValidator.areAllNodesAreInWhitelist(
Lists.newArrayList(enodeURL), permissioningConfiguration);
} catch (Exception e) {
fail(
"Exception not expected. Validation of nodes in whitelist should ignore the optional discovery port param.");
}
}
}