Skip to content

Commit 5fe36c1

Browse files
committed
Extend URI configuration with schemes: "bolt+s", "bolt+ssc", "neo4j+s" and "neo4j+ssc" to allow encryption and trust settings to be configurable using the URI.
1 parent 0f04025 commit 5fe36c1

24 files changed

+552
-122
lines changed

driver/src/main/java/org/neo4j/driver/Config.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.neo4j.driver.exceptions.ServiceUnavailableException;
3131
import org.neo4j.driver.exceptions.SessionExpiredException;
3232
import org.neo4j.driver.exceptions.TransientException;
33+
import org.neo4j.driver.internal.SecuritySettings;
3334
import org.neo4j.driver.internal.async.pool.PoolSettings;
3435
import org.neo4j.driver.internal.cluster.RoutingSettings;
3536
import org.neo4j.driver.internal.handlers.pulln.FetchSizeUtil;
@@ -39,7 +40,6 @@
3940
import org.neo4j.driver.util.Immutable;
4041
import org.neo4j.driver.util.Resource;
4142

42-
import static org.neo4j.driver.Config.TrustStrategy.trustSystemCertificates;
4343
import static org.neo4j.driver.Logging.javaUtilLogging;
4444

4545
/**
@@ -85,11 +85,7 @@ public class Config
8585
private final long maxConnectionLifetimeMillis;
8686
private final long connectionAcquisitionTimeoutMillis;
8787

88-
/** Indicator for encrypted traffic */
89-
private final boolean encrypted;
90-
91-
/** Strategy for how to trust encryption certificate */
92-
private final TrustStrategy trustStrategy;
88+
private final SecuritySettings securitySettings;
9389

9490
private final int routingFailureLimit;
9591
private final long routingRetryDelayMillis;
@@ -113,8 +109,8 @@ private Config( ConfigBuilder builder )
113109
this.maxConnectionPoolSize = builder.maxConnectionPoolSize;
114110
this.connectionAcquisitionTimeoutMillis = builder.connectionAcquisitionTimeoutMillis;
115111

116-
this.encrypted = builder.encrypted;
117-
this.trustStrategy = builder.trustStrategy;
112+
this.securitySettings = builder.securitySettingsBuilder.build();
113+
118114
this.routingFailureLimit = builder.routingFailureLimit;
119115
this.routingRetryDelayMillis = builder.routingRetryDelayMillis;
120116
this.connectionTimeoutMillis = builder.connectionTimeoutMillis;
@@ -190,15 +186,15 @@ public long connectionAcquisitionTimeoutMillis()
190186
*/
191187
public boolean encrypted()
192188
{
193-
return encrypted;
189+
return securitySettings.encrypted();
194190
}
195191

196192
/**
197193
* @return the strategy to use to determine the authenticity of an encryption certificate provided by the Neo4j instance we are connecting to.
198194
*/
199195
public TrustStrategy trustStrategy()
200196
{
201-
return trustStrategy;
197+
return securitySettings.trustStrategy();
202198
}
203199

204200
/**
@@ -229,6 +225,14 @@ public static Config defaultConfig()
229225
return EMPTY;
230226
}
231227

228+
/**
229+
* @return the security setting to use when creating connections.
230+
*/
231+
SecuritySettings securitySettings()
232+
{
233+
return securitySettings;
234+
}
235+
232236
RoutingSettings routingSettings()
233237
{
234238
return new RoutingSettings( routingFailureLimit, routingRetryDelayMillis, routingTablePurgeDelayMillis );
@@ -268,8 +272,7 @@ public static class ConfigBuilder
268272
private long idleTimeBeforeConnectionTest = PoolSettings.DEFAULT_IDLE_TIME_BEFORE_CONNECTION_TEST;
269273
private long maxConnectionLifetimeMillis = PoolSettings.DEFAULT_MAX_CONNECTION_LIFETIME;
270274
private long connectionAcquisitionTimeoutMillis = PoolSettings.DEFAULT_CONNECTION_ACQUISITION_TIMEOUT;
271-
private boolean encrypted = false;
272-
private TrustStrategy trustStrategy = trustSystemCertificates();
275+
private final SecuritySettings.SecuritySettingsBuilder securitySettingsBuilder = new SecuritySettings.SecuritySettingsBuilder();
273276
private int routingFailureLimit = RoutingSettings.DEFAULT.maxRoutingFailures();
274277
private long routingRetryDelayMillis = RoutingSettings.DEFAULT.retryTimeoutDelay();
275278
private long routingTablePurgeDelayMillis = RoutingSettings.DEFAULT.routingTablePurgeDelayMs();
@@ -443,7 +446,7 @@ public ConfigBuilder withConnectionAcquisitionTimeout( long value, TimeUnit unit
443446
*/
444447
public ConfigBuilder withEncryption()
445448
{
446-
this.encrypted = true;
449+
securitySettingsBuilder.withEncryption();
447450
return this;
448451
}
449452

@@ -453,7 +456,7 @@ public ConfigBuilder withEncryption()
453456
*/
454457
public ConfigBuilder withoutEncryption()
455458
{
456-
this.encrypted = false;
459+
securitySettingsBuilder.withoutEncryption();
457460
return this;
458461
}
459462

@@ -473,7 +476,7 @@ public ConfigBuilder withoutEncryption()
473476
*/
474477
public ConfigBuilder withTrustStrategy( TrustStrategy trustStrategy )
475478
{
476-
this.trustStrategy = trustStrategy;
479+
securitySettingsBuilder.withTrustStrategy( trustStrategy );
477480
return this;
478481
}
479482

driver/src/main/java/org/neo4j/driver/GraphDatabase.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@
2222

2323
import org.neo4j.driver.exceptions.ServiceUnavailableException;
2424
import org.neo4j.driver.internal.DriverFactory;
25+
import org.neo4j.driver.internal.Scheme;
26+
import org.neo4j.driver.internal.SecuritySettings;
2527
import org.neo4j.driver.internal.cluster.RoutingSettings;
2628
import org.neo4j.driver.internal.retry.RetrySettings;
29+
import org.neo4j.driver.internal.security.SecurityPlan;
2730

28-
import static org.neo4j.driver.internal.DriverFactory.BOLT_ROUTING_URI_SCHEME;
31+
import static org.neo4j.driver.internal.Scheme.NEO4J_URI_SCHEME;
2932

3033
/**
3134
* Creates {@link Driver drivers}, optionally letting you {@link #driver(URI, Config)} to configure them.
@@ -132,8 +135,10 @@ public static Driver driver( URI uri, AuthToken authToken, Config config )
132135
config = getOrDefault( config );
133136
RoutingSettings routingSettings = config.routingSettings();
134137
RetrySettings retrySettings = config.retrySettings();
135-
136-
return new DriverFactory().newInstance( uri, authToken, routingSettings, retrySettings, config );
138+
SecuritySettings securitySettings = config.securitySettings();
139+
Scheme.validateScheme( uri.getScheme() );
140+
SecurityPlan securityPlan = securitySettings.createSecurityPlan( uri.getScheme() );
141+
return new DriverFactory().newInstance( uri, authToken, routingSettings, retrySettings, config, securityPlan );
137142
}
138143

139144
/**
@@ -192,10 +197,10 @@ private static void assertRoutingUris( Iterable<URI> uris )
192197
{
193198
for ( URI uri : uris )
194199
{
195-
if ( !BOLT_ROUTING_URI_SCHEME.equals( uri.getScheme() ) )
200+
if ( !NEO4J_URI_SCHEME.equals( uri.getScheme() ) )
196201
{
197202
throw new IllegalArgumentException(
198-
"Illegal URI scheme, expected '" + BOLT_ROUTING_URI_SCHEME + "' in '" + uri + "'" );
203+
"Illegal URI scheme, expected '" + NEO4J_URI_SCHEME + "' in '" + uri + "'" );
199204
}
200205
}
201206
}

driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java

Lines changed: 13 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@
2323
import io.netty.util.concurrent.EventExecutorGroup;
2424
import io.netty.util.internal.logging.InternalLoggerFactory;
2525

26-
import java.io.IOException;
2726
import java.net.URI;
28-
import java.security.GeneralSecurityException;
2927

3028
import org.neo4j.driver.AuthToken;
3129
import org.neo4j.driver.AuthTokens;
@@ -50,7 +48,6 @@
5048
import org.neo4j.driver.internal.retry.ExponentialBackoffRetryLogic;
5149
import org.neo4j.driver.internal.retry.RetryLogic;
5250
import org.neo4j.driver.internal.retry.RetrySettings;
53-
import org.neo4j.driver.internal.security.SecurityPlanImpl;
5451
import org.neo4j.driver.internal.security.SecurityPlan;
5552
import org.neo4j.driver.internal.spi.ConnectionPool;
5653
import org.neo4j.driver.internal.spi.ConnectionProvider;
@@ -59,24 +56,22 @@
5956
import org.neo4j.driver.net.ServerAddressResolver;
6057

6158
import static java.lang.String.format;
59+
import static org.neo4j.driver.internal.Scheme.isRoutingScheme;
6260
import static org.neo4j.driver.internal.cluster.IdentityResolver.IDENTITY_RESOLVER;
6361
import static org.neo4j.driver.internal.metrics.MetricsProvider.METRICS_DISABLED_PROVIDER;
64-
import static org.neo4j.driver.internal.security.SecurityPlanImpl.insecure;
6562
import static org.neo4j.driver.internal.util.ErrorUtil.addSuppressed;
6663

6764
public class DriverFactory
6865
{
69-
public static final String BOLT_URI_SCHEME = "bolt";
70-
public static final String BOLT_ROUTING_URI_SCHEME = "neo4j";
7166

7267
public final Driver newInstance( URI uri, AuthToken authToken, RoutingSettings routingSettings,
73-
RetrySettings retrySettings, Config config )
68+
RetrySettings retrySettings, Config config, SecurityPlan securityPlan )
7469
{
75-
return newInstance( uri, authToken, routingSettings, retrySettings, config, null, null );
70+
return newInstance( uri, authToken, routingSettings, retrySettings, config, null, securityPlan );
7671
}
7772

7873
public final Driver newInstance ( URI uri, AuthToken authToken, RoutingSettings routingSettings,
79-
RetrySettings retrySettings, Config config, EventLoopGroup eventLoopGroup, SecurityPlan customSecurityPlan )
74+
RetrySettings retrySettings, Config config, EventLoopGroup eventLoopGroup, SecurityPlan securityPlan )
8075
{
8176
Bootstrap bootstrap;
8277
boolean ownsEventLoopGroup;
@@ -96,16 +91,6 @@ public final Driver newInstance ( URI uri, AuthToken authToken, RoutingSettings
9691
BoltServerAddress address = new BoltServerAddress( uri );
9792
RoutingSettings newRoutingSettings = routingSettings.withRoutingContext( new RoutingContext( uri ) );
9893

99-
SecurityPlan securityPlan;
100-
if ( customSecurityPlan != null )
101-
{
102-
securityPlan = customSecurityPlan;
103-
}
104-
else
105-
{
106-
securityPlan = createSecurityPlan( address, config );
107-
}
108-
10994
InternalLoggerFactory.setDefaultFactory( new NettyLogging( config.logging() ) );
11095
EventExecutorGroup eventExecutorGroup = bootstrap.config().group();
11196
RetryLogic retryLogic = createRetryLogic( retrySettings, eventExecutorGroup, config.logging() );
@@ -148,21 +133,23 @@ protected ChannelConnector createConnector( ConnectionSettings settings, Securit
148133
}
149134

150135
private InternalDriver createDriver( URI uri, SecurityPlan securityPlan, BoltServerAddress address, ConnectionPool connectionPool,
151-
EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic, MetricsProvider metricsProvider, Config config )
136+
EventExecutorGroup eventExecutorGroup, RoutingSettings routingSettings, RetryLogic retryLogic,
137+
MetricsProvider metricsProvider, Config config )
152138
{
153139
try
154140
{
155141
String scheme = uri.getScheme().toLowerCase();
156-
switch ( scheme )
142+
143+
if ( isRoutingScheme( scheme ) )
144+
{
145+
return createRoutingDriver( securityPlan, address, connectionPool, eventExecutorGroup, routingSettings, retryLogic, metricsProvider, config );
146+
}
147+
else if ( !isRoutingScheme( scheme ) )
157148
{
158-
case BOLT_URI_SCHEME:
159149
assertNoRoutingContext( uri, routingSettings );
160150
return createDirectDriver( securityPlan, address, connectionPool, retryLogic, metricsProvider, config );
161-
case BOLT_ROUTING_URI_SCHEME:
162-
return createRoutingDriver( securityPlan, address, connectionPool, eventExecutorGroup, routingSettings, retryLogic, metricsProvider, config );
163-
default:
164-
throw new ClientException( format( "Unsupported URI scheme: %s", scheme ) );
165151
}
152+
throw new ClientException( format( "Unsupported URI scheme: %s", scheme ) );
166153
}
167154
catch ( Throwable driverError )
168155
{
@@ -287,47 +274,6 @@ protected Bootstrap createBootstrap( EventLoopGroup eventLoopGroup )
287274
return BootstrapFactory.newBootstrap( eventLoopGroup );
288275
}
289276

290-
private static SecurityPlan createSecurityPlan( BoltServerAddress address, Config config )
291-
{
292-
try
293-
{
294-
return createSecurityPlanImpl( config );
295-
}
296-
catch ( GeneralSecurityException | IOException ex )
297-
{
298-
throw new ClientException( "Unable to establish SSL parameters", ex );
299-
}
300-
}
301-
302-
/*
303-
* Establish a complete SecurityPlan based on the details provided for
304-
* driver construction.
305-
*/
306-
private static SecurityPlan createSecurityPlanImpl( Config config )
307-
throws GeneralSecurityException, IOException
308-
{
309-
if ( config.encrypted() )
310-
{
311-
Config.TrustStrategy trustStrategy = config.trustStrategy();
312-
boolean hostnameVerificationEnabled = trustStrategy.isHostnameVerificationEnabled();
313-
switch ( trustStrategy.strategy() )
314-
{
315-
case TRUST_CUSTOM_CA_SIGNED_CERTIFICATES:
316-
return SecurityPlanImpl.forCustomCASignedCertificates( trustStrategy.certFile(), hostnameVerificationEnabled );
317-
case TRUST_SYSTEM_CA_SIGNED_CERTIFICATES:
318-
return SecurityPlanImpl.forSystemCASignedCertificates( hostnameVerificationEnabled );
319-
case TRUST_ALL_CERTIFICATES:
320-
return SecurityPlanImpl.forAllCertificates( hostnameVerificationEnabled );
321-
default:
322-
throw new ClientException(
323-
"Unknown TLS authentication strategy: " + trustStrategy.strategy().name() );
324-
}
325-
}
326-
else
327-
{
328-
return insecure();
329-
}
330-
}
331277

332278
private static void assertNoRoutingContext( URI uri, RoutingSettings routingSettings )
333279
{
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2002-2020 "Neo4j,"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.neo4j.driver.internal;
20+
21+
public class Scheme
22+
{
23+
public static final String BOLT_URI_SCHEME = "bolt";
24+
public static final String BOLT_HIGH_TRUST_URI_SCHEME = "bolt+s";
25+
public static final String BOLT_LOW_TRUST_URI_SCHEME = "bolt+ssc";
26+
public static final String NEO4J_URI_SCHEME = "neo4j";
27+
public static final String NEO4J_HIGH_TRUST_URI_SCHEME = "neo4j+s";
28+
public static final String NEO4J_LOW_TRUST_URI_SCHEME = "neo4j+ssc";
29+
30+
public static void validateScheme( String scheme )
31+
{
32+
if ( scheme == null )
33+
{
34+
throw new IllegalArgumentException( "Scheme must not be null" );
35+
}
36+
switch ( scheme )
37+
{
38+
case BOLT_URI_SCHEME:
39+
case BOLT_LOW_TRUST_URI_SCHEME:
40+
case BOLT_HIGH_TRUST_URI_SCHEME:
41+
case NEO4J_URI_SCHEME:
42+
case NEO4J_LOW_TRUST_URI_SCHEME:
43+
case NEO4J_HIGH_TRUST_URI_SCHEME:
44+
return;
45+
default:
46+
throw new IllegalArgumentException( "Invalid address format " + scheme );
47+
}
48+
}
49+
50+
public static boolean isHighTrustScheme( String scheme )
51+
{
52+
return scheme.equals( BOLT_HIGH_TRUST_URI_SCHEME ) || scheme.equals( NEO4J_HIGH_TRUST_URI_SCHEME );
53+
}
54+
55+
public static boolean isLowTrustScheme( String scheme )
56+
{
57+
return scheme.equals( BOLT_LOW_TRUST_URI_SCHEME ) || scheme.equals( NEO4J_LOW_TRUST_URI_SCHEME );
58+
}
59+
60+
public static boolean isSecurityScheme( String scheme )
61+
{
62+
return scheme.equals( BOLT_LOW_TRUST_URI_SCHEME ) || scheme.equals( NEO4J_LOW_TRUST_URI_SCHEME )
63+
|| scheme.equals( BOLT_HIGH_TRUST_URI_SCHEME ) || scheme.equals( NEO4J_HIGH_TRUST_URI_SCHEME );
64+
}
65+
66+
public static boolean isRoutingScheme( String scheme )
67+
{
68+
return scheme.equals( NEO4J_LOW_TRUST_URI_SCHEME ) || scheme.equals( NEO4J_HIGH_TRUST_URI_SCHEME )
69+
|| scheme.equals( NEO4J_URI_SCHEME );
70+
}
71+
}

0 commit comments

Comments
 (0)