mirror of https://github.com/hyperledger/besu
Use the node's configuration to decide if adding a peer with DNS in the enode is allowed (#5584)
* Use the node's configuration to decide if adding a peer with DNS in the enode is allowed Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Update command test mocks Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Update besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com> Signed-off-by: Matt Whitehead <matthew1001@hotmail.com> * Address PR comments. Add a reference in the change log. Fix failing integration test. Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Add the same DNS-config checking logic to admin_removePeer, along with a unit test file for it Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Tweak the change log Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Add clearer error messages for the cases where enode DNS is disabled (but a hostname one has been specified in the URL) or where DNS name resolution failed Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Spotless Java fixes Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Fix copyright for new file Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com> Signed-off-by: Matt Whitehead <matthew1001@hotmail.com> * Address PR comments (mainly copyright & constant renaming) Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * move changelog entry to 23.4.4 Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> --------- Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> Signed-off-by: Matt Whitehead <matthew1001@hotmail.com> Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> Co-authored-by: Matthew Whitehead <matthew1001@gmail.com> Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>pull/5627/head
parent
8f9882f768
commit
5bff76f107
@ -0,0 +1,258 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu contributors |
||||
* |
||||
* 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.ethereum.api.jsonrpc.internal.methods; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.ArgumentMatchers.any; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; |
||||
import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException; |
||||
import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration; |
||||
|
||||
import java.util.Optional; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.mockito.Mock; |
||||
import org.mockito.junit.MockitoJUnitRunner; |
||||
|
||||
@RunWith(MockitoJUnitRunner.StrictStubs.class) |
||||
public class AdminRemovePeerTest { |
||||
|
||||
@Mock private P2PNetwork p2pNetwork; |
||||
|
||||
private AdminRemovePeer method; |
||||
private AdminRemovePeer methodDNSDisabled; |
||||
private AdminRemovePeer methodDNSUpdateDisabled; |
||||
|
||||
final String validEnode = |
||||
"enode://" |
||||
+ "00000000000000000000000000000000" |
||||
+ "00000000000000000000000000000000" |
||||
+ "00000000000000000000000000000000" |
||||
+ "00000000000000000000000000000000" |
||||
+ "@127.0.0.1:30303"; |
||||
|
||||
final String validDNSEnode = |
||||
"enode://" |
||||
+ "00000000000000000000000000000000" |
||||
+ "00000000000000000000000000000000" |
||||
+ "00000000000000000000000000000000" |
||||
+ "00000000000000000000000000000000" |
||||
+ "@node.acme.com:30303"; |
||||
|
||||
final JsonRpcRequestContext validRequest = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {validEnode})); |
||||
|
||||
final JsonRpcRequestContext validDNSRequest = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {validDNSEnode})); |
||||
|
||||
@Before |
||||
public void setup() { |
||||
method = |
||||
new AdminRemovePeer( |
||||
p2pNetwork, |
||||
Optional.of( |
||||
ImmutableEnodeDnsConfiguration.builder() |
||||
.dnsEnabled(true) |
||||
.updateEnabled(true) |
||||
.build())); |
||||
methodDNSDisabled = |
||||
new AdminRemovePeer( |
||||
p2pNetwork, |
||||
Optional.of( |
||||
ImmutableEnodeDnsConfiguration.builder() |
||||
.dnsEnabled(false) |
||||
.updateEnabled(true) |
||||
.build())); |
||||
methodDNSUpdateDisabled = |
||||
new AdminRemovePeer( |
||||
p2pNetwork, |
||||
Optional.of( |
||||
ImmutableEnodeDnsConfiguration.builder() |
||||
.dnsEnabled(true) |
||||
.updateEnabled(false) |
||||
.build())); |
||||
} |
||||
|
||||
@Test |
||||
public void requestIsMissingParameter() { |
||||
final JsonRpcRequestContext request = |
||||
new JsonRpcRequestContext(new JsonRpcRequest("2.0", "admin_removePeer", new String[] {})); |
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(request); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestHasNullObjectParameter() { |
||||
final JsonRpcRequestContext request = |
||||
new JsonRpcRequestContext(new JsonRpcRequest("2.0", "admin_removePeer", null)); |
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(request); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestHasNullArrayParameter() { |
||||
final JsonRpcRequestContext request = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {null})); |
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(request); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestHasInvalidEnode() { |
||||
final JsonRpcRequestContext request = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {"asdf"})); |
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.PARSE_ERROR); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(request); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestHasInvalidEnodeLength() { |
||||
String invalidLengthEnode = |
||||
"enode://" |
||||
+ "0000000000000000000000000000000" |
||||
+ "00000000000000000000000000000000" |
||||
+ "00000000000000000000000000000000" |
||||
+ "00000000000000000000000000000000" |
||||
+ "@127.0.0.1:30303"; |
||||
final JsonRpcRequestContext request = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {invalidLengthEnode})); |
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.ENODE_ID_INVALID); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(request); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestRemovesValidEnode() { |
||||
when(p2pNetwork.removeMaintainedConnectionPeer(any())).thenReturn(true); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcSuccessResponse(validRequest.getRequest().getId(), true); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(validRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestRemovesValidDNSEnode() { |
||||
when(p2pNetwork.removeMaintainedConnectionPeer(any())).thenReturn(true); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcSuccessResponse( |
||||
validRequest.getRequest().getId(), |
||||
true); // DNS is mapped to an IP address, so we expect the non-DNS response
|
||||
|
||||
final JsonRpcResponse actualResponse = method.response(validDNSRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestRemovesDNSEnodeButDNSDisabled() { |
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
validDNSRequest.getRequest().getId(), JsonRpcError.DNS_NOT_ENABLED); |
||||
|
||||
final JsonRpcResponse actualResponse = methodDNSDisabled.response(validDNSRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestRemovesDNSEnodeButDNSNotResolved() { |
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
validDNSRequest.getRequest().getId(), JsonRpcError.CANT_RESOLVE_PEER_ENODE_DNS); |
||||
|
||||
final JsonRpcResponse actualResponse = methodDNSUpdateDisabled.response(validDNSRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestRefusesListOfNodes() { |
||||
final JsonRpcRequestContext request = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {validEnode, validEnode})); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(request); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestReturnsFalseIfRemoveFails() { |
||||
when(p2pNetwork.removeMaintainedConnectionPeer(any())).thenReturn(false); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcSuccessResponse(validRequest.getRequest().getId(), false); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(validRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void requestReturnsErrorWhenP2pDisabled() { |
||||
when(p2pNetwork.removeMaintainedConnectionPeer(any())) |
||||
.thenThrow( |
||||
new P2PDisabledException( |
||||
"P2P networking disabled. Unable to connect to remove peer.")); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse(validRequest.getRequest().getId(), JsonRpcError.P2P_DISABLED); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(validRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
} |
Loading…
Reference in new issue