Skip to content

Commit b0ba747

Browse files
committed
Block untrusted servers
1 parent 0041aac commit b0ba747

File tree

5 files changed

+91
-19
lines changed

5 files changed

+91
-19
lines changed

driver/src/main/java/org/neo4j/driver/internal/handlers/InitResponseHandler.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.neo4j.driver.internal.spi.ResponseHandler;
2929
import org.neo4j.driver.internal.util.ServerVersion;
3030
import org.neo4j.driver.v1.Value;
31+
import org.neo4j.driver.v1.exceptions.UntrustedServerException;
3132

3233
import static org.neo4j.driver.internal.async.ChannelAttributes.setServerVersion;
3334

@@ -71,11 +72,25 @@ public void onRecord( Value[] fields )
7172
throw new UnsupportedOperationException();
7273
}
7374

74-
private static ServerVersion extractServerVersion( Map<String,Value> metadata )
75+
private static ServerVersion extractServerVersion( Map<String,Value> metadata ) throws UntrustedServerException
7576
{
7677
Value versionValue = metadata.get( "server" );
77-
boolean versionAbsent = versionValue == null || versionValue.isNull();
78-
return versionAbsent ? ServerVersion.v3_0_0 : ServerVersion.version( versionValue.asString() );
78+
if ( versionValue == null || versionValue.isNull() )
79+
{
80+
return ServerVersion.v3_0_0;
81+
}
82+
else
83+
{
84+
ServerVersion server = ServerVersion.version(versionValue.asString());
85+
if ( server.product().equalsIgnoreCase( "Neo4j" ) )
86+
{
87+
return server;
88+
}
89+
else
90+
{
91+
throw new UntrustedServerException( "Server does not identify as a genuine Neo4j instance" );
92+
}
93+
}
7994
}
8095

8196
private static void updatePipelineIfNeeded( ServerVersion serverVersion, ChannelPipeline pipeline )

driver/src/main/java/org/neo4j/driver/internal/util/ServerVersion.java

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package org.neo4j.driver.internal.util;
2020

21+
import java.util.Objects;
2122
import java.util.regex.Matcher;
2223
import java.util.regex.Pattern;
2324

@@ -28,28 +29,35 @@
2829

2930
public class ServerVersion
3031
{
31-
public static final ServerVersion v3_5_0 = new ServerVersion( 3, 5, 0 );
32-
public static final ServerVersion v3_4_0 = new ServerVersion( 3, 4, 0 );
33-
public static final ServerVersion v3_2_0 = new ServerVersion( 3, 2, 0 );
34-
public static final ServerVersion v3_1_0 = new ServerVersion( 3, 1, 0 );
35-
public static final ServerVersion v3_0_0 = new ServerVersion( 3, 0, 0 );
36-
public static final ServerVersion vInDev = new ServerVersion( Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE );
32+
public static final ServerVersion v3_5_0 = new ServerVersion( "Neo4j", 3, 5, 0 );
33+
public static final ServerVersion v3_4_0 = new ServerVersion( "Neo4j", 3, 4, 0 );
34+
public static final ServerVersion v3_2_0 = new ServerVersion( "Neo4j", 3, 2, 0 );
35+
public static final ServerVersion v3_1_0 = new ServerVersion( "Neo4j", 3, 1, 0 );
36+
public static final ServerVersion v3_0_0 = new ServerVersion( "Neo4j", 3, 0, 0 );
37+
public static final ServerVersion vInDev = new ServerVersion( "Neo4j", Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE );
3738

3839
private static final String NEO4J_IN_DEV_VERSION_STRING = "Neo4j/dev";
3940
private static final Pattern PATTERN =
40-
Pattern.compile( "(Neo4j/)?(\\d+)\\.(\\d+)(?:\\.)?(\\d*)(\\.|-|\\+)?([0-9A-Za-z-.]*)?" );
41+
Pattern.compile( "([^/]*)/(\\d+)\\.(\\d+)(?:\\.)?(\\d*)(\\.|-|\\+)?([0-9A-Za-z-.]*)?" );
4142

43+
private final String product;
4244
private final int major;
4345
private final int minor;
4446
private final int patch;
4547
private final String stringValue;
4648

47-
private ServerVersion( int major, int minor, int patch )
49+
private ServerVersion( String product, int major, int minor, int patch )
4850
{
51+
this.product = product;
4952
this.major = major;
5053
this.minor = minor;
5154
this.patch = patch;
52-
this.stringValue = stringValue( major, minor, patch );
55+
this.stringValue = stringValue( product, major, minor, patch );
56+
}
57+
58+
public String product()
59+
{
60+
return product;
5361
}
5462

5563
public static ServerVersion version( Driver driver )
@@ -72,6 +80,7 @@ public static ServerVersion version( String server )
7280
Matcher matcher = PATTERN.matcher( server );
7381
if ( matcher.matches() )
7482
{
83+
String product = matcher.group( 1 );
7584
int major = Integer.valueOf( matcher.group( 2 ) );
7685
int minor = Integer.valueOf( matcher.group( 3 ) );
7786
String patchString = matcher.group( 4 );
@@ -80,7 +89,7 @@ public static ServerVersion version( String server )
8089
{
8190
patch = Integer.valueOf( patchString );
8291
}
83-
return new ServerVersion( major, minor, patch );
92+
return new ServerVersion( product, major, minor, patch );
8493
}
8594
else if ( server.equalsIgnoreCase( NEO4J_IN_DEV_VERSION_STRING ) )
8695
{
@@ -103,6 +112,8 @@ public boolean equals( Object o )
103112

104113
ServerVersion that = (ServerVersion) o;
105114

115+
if ( !product.equals( that.product ) )
116+
{ return false; }
106117
if ( major != that.major )
107118
{ return false; }
108119
if ( minor != that.minor )
@@ -113,10 +124,7 @@ public boolean equals( Object o )
113124
@Override
114125
public int hashCode()
115126
{
116-
int result = major;
117-
result = 31 * result + minor;
118-
result = 31 * result + patch;
119-
return result;
127+
return Objects.hash(product, major, minor, patch);
120128
}
121129

122130
public boolean greaterThan(ServerVersion other)
@@ -141,6 +149,10 @@ public boolean lessThanOrEqual(ServerVersion other)
141149

142150
private int compareTo( ServerVersion o )
143151
{
152+
if ( !product.equals( o.product ) )
153+
{
154+
throw new IllegalArgumentException("Comparing different products");
155+
}
144156
int c = compare( major, o.major );
145157
if (c == 0)
146158
{
@@ -160,12 +172,12 @@ public String toString()
160172
return stringValue;
161173
}
162174

163-
private static String stringValue( int major, int minor, int patch )
175+
private static String stringValue( String product, int major, int minor, int patch )
164176
{
165177
if ( major == Integer.MAX_VALUE && minor == Integer.MAX_VALUE && patch == Integer.MAX_VALUE )
166178
{
167179
return NEO4J_IN_DEV_VERSION_STRING;
168180
}
169-
return String.format( "Neo4j/%s.%s.%s", major, minor, patch );
181+
return String.format( "%s/%s.%s.%s", product, major, minor, patch );
170182
}
171183
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.neo4j.driver.v1.exceptions;
2+
3+
/**
4+
* Thrown if the remote server cannot be verified as Neo4j.
5+
*/
6+
public class UntrustedServerException extends RuntimeException
7+
{
8+
public UntrustedServerException(String message)
9+
{
10+
super(message);
11+
}
12+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.neo4j.driver.internal;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.neo4j.driver.v1.Config;
5+
import org.neo4j.driver.v1.GraphDatabase;
6+
import org.neo4j.driver.v1.exceptions.UntrustedServerException;
7+
import org.neo4j.driver.v1.util.StubServer;
8+
9+
import static org.hamcrest.core.IsEqual.equalTo;
10+
import static org.hamcrest.junit.MatcherAssert.assertThat;
11+
import static org.junit.jupiter.api.Assertions.assertThrows;
12+
import static org.neo4j.driver.v1.Logging.none;
13+
14+
public class TrustedServerProductTest
15+
{
16+
private static final Config config = Config.build()
17+
.withoutEncryption()
18+
.withLogging( none() )
19+
.toConfig();
20+
21+
@Test
22+
void shouldRejectConnectionsToNonNeo4jServers() throws Exception
23+
{
24+
StubServer server = StubServer.start( "untrusted_server.script", 9001 );
25+
assertThrows( UntrustedServerException.class, () -> GraphDatabase.driver( "bolt://127.0.0.1:9001", config ));
26+
assertThat( server.exitStatus(), equalTo( 0 ) );
27+
}
28+
29+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
!: AUTO RESET
2+
3+
C: INIT "neo4j-java/dev" {"scheme": "none"}
4+
S: SUCCESS {"server": "AgentSmith/0.0.1"}

0 commit comments

Comments
 (0)