Polish "Add auto-configuration for Neo4j driver"
See gh-22301
This commit is contained in:
@@ -34,7 +34,6 @@ import org.springframework.boot.build.context.properties.DocumentOptions.Builder
|
||||
* {@link Task} used to document auto-configuration classes.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
public class DocumentConfigurationProperties extends DefaultTask {
|
||||
|
||||
|
||||
@@ -16,22 +16,23 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.neo4j;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.neo4j.driver.net.ServerAddress;
|
||||
import org.neo4j.driver.net.ServerAddressResolver;
|
||||
import org.neo4j.driver.Config;
|
||||
import org.neo4j.driver.Config.ConfigBuilder;
|
||||
|
||||
/**
|
||||
* Resolver used only for configuration tests.
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link Config} via a {@link ConfigBuilder} whilst retaining default auto-configuration.
|
||||
*
|
||||
* @author Michael J. Simons
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.4.0
|
||||
*/
|
||||
class TestServerAddressResolver implements ServerAddressResolver {
|
||||
@FunctionalInterface
|
||||
public interface ConfigBuilderCustomizer {
|
||||
|
||||
@Override
|
||||
public Set<ServerAddress> resolve(ServerAddress address) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
/**
|
||||
* Customize the {@link ConfigBuilder}.
|
||||
* @param configBuilder the {@link ConfigBuilder} to customize
|
||||
*/
|
||||
void customize(ConfigBuilder configBuilder);
|
||||
|
||||
}
|
||||
@@ -19,20 +19,25 @@ package org.springframework.boot.autoconfigure.neo4j;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.neo4j.driver.AuthToken;
|
||||
import org.neo4j.driver.AuthTokens;
|
||||
import org.neo4j.driver.Config;
|
||||
import org.neo4j.driver.Config.TrustStrategy;
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.neo4j.driver.GraphDatabase;
|
||||
import org.neo4j.driver.internal.Scheme;
|
||||
import org.neo4j.driver.net.ServerAddressResolver;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.Pool;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.Security;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -40,9 +45,10 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Automatic configuration of Neo4j's Java Driver.
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Neo4j.
|
||||
*
|
||||
* @author Michael J. Simons
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.4.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -51,14 +57,16 @@ import org.springframework.util.StringUtils;
|
||||
public class Neo4jAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Driver.class)
|
||||
Driver neo4jDriver(Neo4jProperties properties) {
|
||||
AuthToken authToken = asAuthToken(properties.getAuthentication());
|
||||
Config config = asDriverConfig(properties);
|
||||
@ConditionalOnMissingBean
|
||||
public Driver neo4jDriver(Neo4jProperties properties,
|
||||
ObjectProvider<ConfigBuilderCustomizer> configBuilderCustomizers) {
|
||||
AuthToken authToken = mapAuthToken(properties.getAuthentication());
|
||||
Config config = mapDriverConfig(properties,
|
||||
configBuilderCustomizers.orderedStream().collect(Collectors.toList()));
|
||||
return GraphDatabase.driver(properties.getUri(), authToken, config);
|
||||
}
|
||||
|
||||
static AuthToken asAuthToken(Neo4jProperties.Authentication authentication) {
|
||||
AuthToken mapAuthToken(Neo4jProperties.Authentication authentication) {
|
||||
String username = authentication.getUsername();
|
||||
String password = authentication.getPassword();
|
||||
String kerberosTicket = authentication.getKerberosTicket();
|
||||
@@ -69,33 +77,30 @@ public class Neo4jAutoConfiguration {
|
||||
boolean hasKerberosTicket = StringUtils.hasText(kerberosTicket);
|
||||
|
||||
if (hasUsername && hasKerberosTicket) {
|
||||
throw new InvalidConfigurationPropertyValueException("org.neo4j.driver.authentication",
|
||||
"username=" + username + ",kerberos-ticket=" + kerberosTicket,
|
||||
"Cannot specify both username and kerberos ticket.");
|
||||
throw new IllegalStateException(String.format(
|
||||
"Cannot specify both username ('%s') and kerberos ticket ('%s')", username, kerberosTicket));
|
||||
}
|
||||
|
||||
if (hasUsername && hasPassword) {
|
||||
return AuthTokens.basic(username, password, realm);
|
||||
}
|
||||
|
||||
if (hasKerberosTicket) {
|
||||
return AuthTokens.kerberos(kerberosTicket);
|
||||
}
|
||||
|
||||
return AuthTokens.none();
|
||||
}
|
||||
|
||||
static Config asDriverConfig(Neo4jProperties properties) {
|
||||
Config mapDriverConfig(Neo4jProperties properties, List<ConfigBuilderCustomizer> customizers) {
|
||||
Config.ConfigBuilder builder = Config.builder();
|
||||
applyTo(builder, properties.getPool());
|
||||
configurePoolSettings(builder, properties.getPool());
|
||||
URI uri = properties.getUri();
|
||||
String scheme = (uri != null) ? uri.getScheme() : "bolt";
|
||||
applyTo(builder, properties.getConfig(), isSimpleScheme(scheme));
|
||||
|
||||
return builder.withLogging(new Neo4jSpringJclLogging()).build();
|
||||
configureDriverSettings(builder, properties, isSimpleScheme(scheme));
|
||||
builder.withLogging(new Neo4jSpringJclLogging());
|
||||
customizers.forEach((customizer) -> customizer.customize(builder));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static boolean isSimpleScheme(String scheme) {
|
||||
private boolean isSimpleScheme(String scheme) {
|
||||
String lowerCaseScheme = scheme.toLowerCase(Locale.ENGLISH);
|
||||
try {
|
||||
Scheme.validateScheme(lowerCaseScheme);
|
||||
@@ -103,24 +108,22 @@ public class Neo4jAutoConfiguration {
|
||||
catch (IllegalArgumentException ex) {
|
||||
throw new IllegalArgumentException(String.format("'%s' is not a supported scheme.", scheme));
|
||||
}
|
||||
|
||||
return lowerCaseScheme.equals("bolt") || lowerCaseScheme.equals("neo4j");
|
||||
}
|
||||
|
||||
private static void applyTo(Config.ConfigBuilder builder, Neo4jProperties.PoolSettings poolSettings) {
|
||||
if (poolSettings.isLogLeakedSessions()) {
|
||||
private void configurePoolSettings(Config.ConfigBuilder builder, Pool pool) {
|
||||
if (pool.isLogLeakedSessions()) {
|
||||
builder.withLeakedSessionsLogging();
|
||||
}
|
||||
builder.withMaxConnectionPoolSize(poolSettings.getMaxConnectionPoolSize());
|
||||
Duration idleTimeBeforeConnectionTest = poolSettings.getIdleTimeBeforeConnectionTest();
|
||||
builder.withMaxConnectionPoolSize(pool.getMaxConnectionPoolSize());
|
||||
Duration idleTimeBeforeConnectionTest = pool.getIdleTimeBeforeConnectionTest();
|
||||
if (idleTimeBeforeConnectionTest != null) {
|
||||
builder.withConnectionLivenessCheckTimeout(idleTimeBeforeConnectionTest.toMillis(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
builder.withMaxConnectionLifetime(poolSettings.getMaxConnectionLifetime().toMillis(), TimeUnit.MILLISECONDS);
|
||||
builder.withConnectionAcquisitionTimeout(poolSettings.getConnectionAcquisitionTimeout().toMillis(),
|
||||
builder.withMaxConnectionLifetime(pool.getMaxConnectionLifetime().toMillis(), TimeUnit.MILLISECONDS);
|
||||
builder.withConnectionAcquisitionTimeout(pool.getConnectionAcquisitionTimeout().toMillis(),
|
||||
TimeUnit.MILLISECONDS);
|
||||
|
||||
if (poolSettings.isMetricsEnabled()) {
|
||||
if (pool.isMetricsEnabled()) {
|
||||
builder.withDriverMetrics();
|
||||
}
|
||||
else {
|
||||
@@ -128,66 +131,56 @@ public class Neo4jAutoConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyTo(Config.ConfigBuilder builder, Neo4jProperties.DriverSettings driverSettings,
|
||||
private void configureDriverSettings(Config.ConfigBuilder builder, Neo4jProperties properties,
|
||||
boolean withEncryptionAndTrustSettings) {
|
||||
if (withEncryptionAndTrustSettings) {
|
||||
applyEncryptionAndTrustSettings(builder, driverSettings);
|
||||
}
|
||||
|
||||
builder.withConnectionTimeout(driverSettings.getConnectionTimeout().toMillis(), TimeUnit.MILLISECONDS);
|
||||
builder.withMaxTransactionRetryTime(driverSettings.getMaxTransactionRetryTime().toMillis(),
|
||||
TimeUnit.MILLISECONDS);
|
||||
|
||||
Class<? extends ServerAddressResolver> serverAddressResolverClass = driverSettings
|
||||
.getServerAddressResolverClass();
|
||||
if (serverAddressResolverClass != null) {
|
||||
builder.withResolver(BeanUtils.instantiateClass(serverAddressResolverClass));
|
||||
applyEncryptionAndTrustSettings(builder, properties.getSecurity());
|
||||
}
|
||||
builder.withConnectionTimeout(properties.getConnectionTimeout().toMillis(), TimeUnit.MILLISECONDS);
|
||||
builder.withMaxTransactionRetryTime(properties.getMaxTransactionRetryTime().toMillis(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private static void applyEncryptionAndTrustSettings(Config.ConfigBuilder builder,
|
||||
Neo4jProperties.DriverSettings driverSettings) {
|
||||
if (driverSettings.isEncrypted()) {
|
||||
private void applyEncryptionAndTrustSettings(Config.ConfigBuilder builder,
|
||||
Neo4jProperties.Security securityProperties) {
|
||||
if (securityProperties.isEncrypted()) {
|
||||
builder.withEncryption();
|
||||
}
|
||||
else {
|
||||
builder.withoutEncryption();
|
||||
}
|
||||
builder.withTrustStrategy(toInternalRepresentation(driverSettings.getTrustSettings()));
|
||||
builder.withTrustStrategy(mapTrustStrategy(securityProperties));
|
||||
}
|
||||
|
||||
static Config.TrustStrategy toInternalRepresentation(Neo4jProperties.TrustSettings trustSettings) {
|
||||
String propertyName = "org.neo4j.driver.config.trust-settings";
|
||||
private Config.TrustStrategy mapTrustStrategy(Neo4jProperties.Security securityProperties) {
|
||||
String propertyName = "spring.neo4j.security.trust-strategy";
|
||||
Security.TrustStrategy strategy = securityProperties.getTrustStrategy();
|
||||
TrustStrategy trustStrategy = createTrustStrategy(securityProperties, propertyName, strategy);
|
||||
if (securityProperties.isHostnameVerificationEnabled()) {
|
||||
trustStrategy.withHostnameVerification();
|
||||
}
|
||||
else {
|
||||
trustStrategy.withoutHostnameVerification();
|
||||
}
|
||||
return trustStrategy;
|
||||
}
|
||||
|
||||
Config.TrustStrategy internalRepresentation;
|
||||
Neo4jProperties.TrustSettings.Strategy strategy = trustSettings.getStrategy();
|
||||
private TrustStrategy createTrustStrategy(Neo4jProperties.Security securityProperties, String propertyName,
|
||||
Security.TrustStrategy strategy) {
|
||||
switch (strategy) {
|
||||
case TRUST_ALL_CERTIFICATES:
|
||||
internalRepresentation = Config.TrustStrategy.trustAllCertificates();
|
||||
break;
|
||||
return TrustStrategy.trustAllCertificates();
|
||||
case TRUST_SYSTEM_CA_SIGNED_CERTIFICATES:
|
||||
internalRepresentation = Config.TrustStrategy.trustSystemCertificates();
|
||||
break;
|
||||
return TrustStrategy.trustSystemCertificates();
|
||||
case TRUST_CUSTOM_CA_SIGNED_CERTIFICATES:
|
||||
File certFile = trustSettings.getCertFile();
|
||||
File certFile = securityProperties.getCertFile();
|
||||
if (certFile == null || !certFile.isFile()) {
|
||||
throw new InvalidConfigurationPropertyValueException(propertyName, strategy.name(),
|
||||
"Configured trust strategy requires a certificate file.");
|
||||
}
|
||||
internalRepresentation = Config.TrustStrategy.trustCustomCertificateSignedBy(certFile);
|
||||
break;
|
||||
return TrustStrategy.trustCustomCertificateSignedBy(certFile);
|
||||
default:
|
||||
throw new InvalidConfigurationPropertyValueException(propertyName, strategy.name(), "Unknown strategy.");
|
||||
}
|
||||
|
||||
if (trustSettings.isHostnameVerificationEnabled()) {
|
||||
internalRepresentation.withHostnameVerification();
|
||||
}
|
||||
else {
|
||||
internalRepresentation.withoutHostnameVerification();
|
||||
}
|
||||
|
||||
return internalRepresentation;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,38 +20,38 @@ import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.neo4j.driver.net.ServerAddressResolver;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Used to configure an instance of the {@link org.neo4j.driver.Driver Neo4j-Java-Driver}.
|
||||
* Configuration properties for Neo4j.
|
||||
*
|
||||
* @author Michael J. Simons
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.4.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.neo4j")
|
||||
public class Neo4jProperties {
|
||||
|
||||
/**
|
||||
* Uri this driver should connect to. The driver supports bolt or neo4j as schemes.
|
||||
* URI used by the driver.
|
||||
*/
|
||||
private URI uri = URI.create("bolt://localhost:7687");
|
||||
|
||||
/**
|
||||
* Authentication the driver is supposed to use. Maybe null.
|
||||
* Timeout for borrowing connections from the pool.
|
||||
*/
|
||||
private Authentication authentication = new Authentication();
|
||||
private Duration connectionTimeout = Duration.ofSeconds(30);
|
||||
|
||||
/**
|
||||
* Configuration of the connection pool.
|
||||
* Maximum time transactions are allowed to retry.
|
||||
*/
|
||||
private PoolSettings pool = new PoolSettings();
|
||||
private Duration maxTransactionRetryTime = Duration.ofSeconds(30);
|
||||
|
||||
/**
|
||||
* Detailed configuration of the driver.
|
||||
*/
|
||||
private DriverSettings config = new DriverSettings();
|
||||
private final Authentication authentication = new Authentication();
|
||||
|
||||
private final Pool pool = new Pool();
|
||||
|
||||
private final Security security = new Security();
|
||||
|
||||
public URI getUri() {
|
||||
return this.uri;
|
||||
@@ -61,39 +61,43 @@ public class Neo4jProperties {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public Duration getConnectionTimeout() {
|
||||
return this.connectionTimeout;
|
||||
}
|
||||
|
||||
public void setConnectionTimeout(Duration connectionTimeout) {
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
|
||||
public Duration getMaxTransactionRetryTime() {
|
||||
return this.maxTransactionRetryTime;
|
||||
}
|
||||
|
||||
public void setMaxTransactionRetryTime(Duration maxTransactionRetryTime) {
|
||||
this.maxTransactionRetryTime = maxTransactionRetryTime;
|
||||
}
|
||||
|
||||
public Authentication getAuthentication() {
|
||||
return this.authentication;
|
||||
}
|
||||
|
||||
public void setAuthentication(Authentication authentication) {
|
||||
this.authentication = authentication;
|
||||
}
|
||||
|
||||
public PoolSettings getPool() {
|
||||
public Pool getPool() {
|
||||
return this.pool;
|
||||
}
|
||||
|
||||
public void setPool(PoolSettings pool) {
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
public DriverSettings getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public void setConfig(DriverSettings config) {
|
||||
this.config = config;
|
||||
public Security getSecurity() {
|
||||
return this.security;
|
||||
}
|
||||
|
||||
public static class Authentication {
|
||||
|
||||
/**
|
||||
* Login of the user connecting to the database.
|
||||
* Login user of the server.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* Password of the user connecting to the database.
|
||||
* Login password of the server.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
@@ -142,26 +146,26 @@ public class Neo4jProperties {
|
||||
|
||||
}
|
||||
|
||||
public static class PoolSettings {
|
||||
public static class Pool {
|
||||
|
||||
/**
|
||||
* Flag, if metrics are enabled.
|
||||
* Whether to enable metrics.
|
||||
*/
|
||||
private boolean metricsEnabled = false;
|
||||
|
||||
/**
|
||||
* Flag, if leaked sessions logging is enabled.
|
||||
* Whether to log leaked sessions.
|
||||
*/
|
||||
private boolean logLeakedSessions = false;
|
||||
|
||||
/**
|
||||
* Maximum amount of connections in the connection pool towards a single database.
|
||||
*/
|
||||
private int maxConnectionPoolSize = org.neo4j.driver.internal.async.pool.PoolSettings.DEFAULT_MAX_CONNECTION_POOL_SIZE;
|
||||
private int maxConnectionPoolSize = 100;
|
||||
|
||||
/**
|
||||
* Pooled connections that have been idle in the pool for longer than this timeout
|
||||
* will be tested before they are used again.
|
||||
* Pooled connections that have been idle in the pool for longer than this
|
||||
* threshold will be tested before they are used again.
|
||||
*/
|
||||
private Duration idleTimeBeforeConnectionTest;
|
||||
|
||||
@@ -169,15 +173,13 @@ public class Neo4jProperties {
|
||||
* Pooled connections older than this threshold will be closed and removed from
|
||||
* the pool.
|
||||
*/
|
||||
private Duration maxConnectionLifetime = Duration
|
||||
.ofMillis(org.neo4j.driver.internal.async.pool.PoolSettings.DEFAULT_MAX_CONNECTION_LIFETIME);
|
||||
private Duration maxConnectionLifetime = Duration.ofHours(1);
|
||||
|
||||
/**
|
||||
* Acquisition of new connections will be attempted for at most configured
|
||||
* timeout.
|
||||
*/
|
||||
private Duration connectionAcquisitionTimeout = Duration
|
||||
.ofMillis(org.neo4j.driver.internal.async.pool.PoolSettings.DEFAULT_CONNECTION_ACQUISITION_TIMEOUT);
|
||||
private Duration connectionAcquisitionTimeout = Duration.ofSeconds(60);
|
||||
|
||||
public boolean isLogLeakedSessions() {
|
||||
return this.logLeakedSessions;
|
||||
@@ -229,35 +231,27 @@ public class Neo4jProperties {
|
||||
|
||||
}
|
||||
|
||||
public static class DriverSettings {
|
||||
public static class Security {
|
||||
|
||||
/**
|
||||
* Flag, if the driver should use encrypted traffic.
|
||||
* Whether the driver should use encrypted traffic.
|
||||
*/
|
||||
private boolean encrypted = false;
|
||||
|
||||
/**
|
||||
* Specify how to determine the authenticity of an encryption certificate provided
|
||||
* by the Neo4j instance we are connecting to.
|
||||
* Trust strategy to use.
|
||||
*/
|
||||
private TrustSettings trustSettings = new TrustSettings();
|
||||
private TrustStrategy trustStrategy = TrustStrategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES;
|
||||
|
||||
/**
|
||||
* Specify socket connection timeout.
|
||||
* Path to the file that holds the trusted certificates.
|
||||
*/
|
||||
private Duration connectionTimeout = Duration.ofSeconds(30);
|
||||
private File certFile;
|
||||
|
||||
/**
|
||||
* Specify the maximum time transactions are allowed to retry.
|
||||
* Whether hostname verification is required.
|
||||
*/
|
||||
private Duration maxTransactionRetryTime = Duration
|
||||
.ofMillis(org.neo4j.driver.internal.retry.RetrySettings.DEFAULT.maxRetryTimeMs());
|
||||
|
||||
/**
|
||||
* Specify a custom server address resolver used by the routing driver to resolve
|
||||
* the initial address used to create the driver.
|
||||
*/
|
||||
private Class<? extends ServerAddressResolver> serverAddressResolverClass;
|
||||
private boolean hostnameVerificationEnabled = true;
|
||||
|
||||
public boolean isEncrypted() {
|
||||
return this.encrypted;
|
||||
@@ -267,73 +261,12 @@ public class Neo4jProperties {
|
||||
this.encrypted = encrypted;
|
||||
}
|
||||
|
||||
public TrustSettings getTrustSettings() {
|
||||
return this.trustSettings;
|
||||
public TrustStrategy getTrustStrategy() {
|
||||
return this.trustStrategy;
|
||||
}
|
||||
|
||||
public void setTrustSettings(TrustSettings trustSettings) {
|
||||
this.trustSettings = trustSettings;
|
||||
}
|
||||
|
||||
public Duration getConnectionTimeout() {
|
||||
return this.connectionTimeout;
|
||||
}
|
||||
|
||||
public void setConnectionTimeout(Duration connectionTimeout) {
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
|
||||
public Duration getMaxTransactionRetryTime() {
|
||||
return this.maxTransactionRetryTime;
|
||||
}
|
||||
|
||||
public void setMaxTransactionRetryTime(Duration maxTransactionRetryTime) {
|
||||
this.maxTransactionRetryTime = maxTransactionRetryTime;
|
||||
}
|
||||
|
||||
public Class<? extends ServerAddressResolver> getServerAddressResolverClass() {
|
||||
return this.serverAddressResolverClass;
|
||||
}
|
||||
|
||||
public void setServerAddressResolverClass(Class<? extends ServerAddressResolver> serverAddressResolverClass) {
|
||||
this.serverAddressResolverClass = serverAddressResolverClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TrustSettings {
|
||||
|
||||
public enum Strategy {
|
||||
|
||||
TRUST_ALL_CERTIFICATES,
|
||||
|
||||
TRUST_CUSTOM_CA_SIGNED_CERTIFICATES,
|
||||
|
||||
TRUST_SYSTEM_CA_SIGNED_CERTIFICATES
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the strategy to use use.
|
||||
*/
|
||||
private Strategy strategy = Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES;
|
||||
|
||||
/**
|
||||
* File of the certificate to use.
|
||||
*/
|
||||
private File certFile;
|
||||
|
||||
/**
|
||||
* Flag, if hostname verification is used.
|
||||
*/
|
||||
private boolean hostnameVerificationEnabled = false;
|
||||
|
||||
public Strategy getStrategy() {
|
||||
return this.strategy;
|
||||
}
|
||||
|
||||
public void setStrategy(Strategy strategy) {
|
||||
this.strategy = strategy;
|
||||
public void setTrustStrategy(TrustStrategy trustStrategy) {
|
||||
this.trustStrategy = trustStrategy;
|
||||
}
|
||||
|
||||
public File getCertFile() {
|
||||
@@ -352,6 +285,25 @@ public class Neo4jProperties {
|
||||
this.hostnameVerificationEnabled = hostnameVerificationEnabled;
|
||||
}
|
||||
|
||||
public enum TrustStrategy {
|
||||
|
||||
/**
|
||||
* Trust all certificates.
|
||||
*/
|
||||
TRUST_ALL_CERTIFICATES,
|
||||
|
||||
/**
|
||||
* Trust certificates that are signed by a trusted certificate.
|
||||
*/
|
||||
TRUST_CUSTOM_CA_SIGNED_CERTIFICATES,
|
||||
|
||||
/**
|
||||
* Trust certificates that can be verified through the local system store.
|
||||
*/
|
||||
TRUST_SYSTEM_CA_SIGNED_CERTIFICATES
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ class Neo4jSpringJclLogging implements Logging {
|
||||
|
||||
@Override
|
||||
public Logger getLog(String name) {
|
||||
|
||||
String requestedLog = name;
|
||||
if (!requestedLog.startsWith(AUTOMATIC_PREFIX)) {
|
||||
requestedLog = AUTOMATIC_PREFIX + name;
|
||||
@@ -46,7 +45,7 @@ class Neo4jSpringJclLogging implements Logging {
|
||||
return new SpringJclLogger(springJclLog);
|
||||
}
|
||||
|
||||
static final class SpringJclLogger implements Logger {
|
||||
private static final class SpringJclLogger implements Logger {
|
||||
|
||||
private final Log delegate;
|
||||
|
||||
|
||||
@@ -35,14 +35,17 @@ import org.springframework.test.context.DynamicPropertySource;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link Neo4jAutoConfiguration}.
|
||||
*
|
||||
* @author Michael J. Simons
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SpringBootTest
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class Neo4jAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
private static Neo4jContainer<?> neo4jServer = new Neo4jContainer<>("neo4j:4.0");
|
||||
private static final Neo4jContainer<?> neo4jServer = new Neo4jContainer<>("neo4j:4.0");
|
||||
|
||||
@DynamicPropertySource
|
||||
static void neo4jProperties(DynamicPropertyRegistry registry) {
|
||||
@@ -51,16 +54,11 @@ class Neo4jAutoConfigurationIntegrationTests {
|
||||
registry.add("spring.neo4j.authentication.password", neo4jServer::getAdminPassword);
|
||||
}
|
||||
|
||||
private final Driver driver;
|
||||
|
||||
@Autowired
|
||||
Neo4jAutoConfigurationIntegrationTests(Driver driver) {
|
||||
this.driver = driver;
|
||||
}
|
||||
private Driver driver;
|
||||
|
||||
@Test
|
||||
void ensureDriverIsOpen() {
|
||||
|
||||
void driverCanHandleRequest() {
|
||||
try (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) {
|
||||
Result statementResult = tx.run("MATCH (n:Thing) RETURN n LIMIT 1");
|
||||
assertThat(statementResult.hasNext()).isFalse();
|
||||
|
||||
@@ -16,24 +16,37 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.neo4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.neo4j.driver.AuthToken;
|
||||
import org.neo4j.driver.AuthTokens;
|
||||
import org.neo4j.driver.Config;
|
||||
import org.neo4j.driver.Config.ConfigBuilder;
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.neo4j.driver.exceptions.ClientException;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.Authentication;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.Security.TrustStrategy;
|
||||
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.mock;
|
||||
import static org.mockito.BDDMockito.when;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link Neo4jAutoConfiguration}.
|
||||
*
|
||||
* @author Michael J. Simons
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class Neo4jAutoConfigurationTests {
|
||||
|
||||
@@ -41,54 +54,220 @@ class Neo4jAutoConfigurationTests {
|
||||
.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void shouldRequireAllNeededClasses() {
|
||||
|
||||
void driverNotConfiguredWithoutDriverApi() {
|
||||
this.contextRunner.withPropertyValues("spring.neo4j.uri=bolt://localhost:4711")
|
||||
.withClassLoader(new FilteredClassLoader(Driver.class))
|
||||
.run((ctx) -> assertThat(ctx).doesNotHaveBean(Driver.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotRequireUri() {
|
||||
|
||||
void driverShouldNotRequireUri() {
|
||||
this.contextRunner.run((ctx) -> assertThat(ctx).hasSingleBean(Driver.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateDriver() {
|
||||
|
||||
void driverShouldInvokeConfigBuilderCustomizers() {
|
||||
this.contextRunner.withPropertyValues("spring.neo4j.uri=bolt://localhost:4711")
|
||||
.run((ctx) -> assertThat(ctx).hasSingleBean(Driver.class));
|
||||
.withBean(ConfigBuilderCustomizer.class, () -> ConfigBuilder::withEncryption)
|
||||
.run((ctx) -> assertThat(ctx.getBean(Driver.class).isEncrypted()).isTrue());
|
||||
}
|
||||
|
||||
/**
|
||||
* These tests assert correct configuration behaviour for cases in which one of the
|
||||
* "advanced" schemes is used to configure the driver. If any of the schemes is used,
|
||||
* than a contradicting explicit configuration will throw an error.
|
||||
* @param scheme The scheme to test.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "bolt+s", "bolt+ssc", "neo4j+s", "neo4j+ssc" })
|
||||
void schemesShouldBeApplied(String scheme) {
|
||||
|
||||
@ValueSource(strings = { "bolt", "neo4j" })
|
||||
void uriWithSimpleSchemeAreDetected(String scheme) {
|
||||
this.contextRunner.withPropertyValues("spring.neo4j.uri=" + scheme + "://localhost:4711").run((ctx) -> {
|
||||
assertThat(ctx).hasSingleBean(Driver.class);
|
||||
assertThat(ctx.getBean(Driver.class).isEncrypted()).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "bolt+s", "bolt+ssc", "neo4j+s", "neo4j+ssc" })
|
||||
void uriWithAdvancedSchemesAreDetected(String scheme) {
|
||||
this.contextRunner.withPropertyValues("spring.neo4j.uri=" + scheme + "://localhost:4711").run((ctx) -> {
|
||||
assertThat(ctx).hasSingleBean(Driver.class);
|
||||
Driver driver = ctx.getBean(Driver.class);
|
||||
assertThat(driver.isEncrypted()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class WithDriver {
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "bolt+routing", "bolt+x", "neo4j+wth" })
|
||||
void uriWithInvalidSchemesAreDetected(String invalidScheme) {
|
||||
this.contextRunner.withPropertyValues("spring.neo4j.uri=" + invalidScheme + "://localhost:4711")
|
||||
.run((ctx) -> assertThat(ctx).hasFailed().getFailure()
|
||||
.hasMessageContaining("'%s' is not a supported scheme.", invalidScheme));
|
||||
}
|
||||
|
||||
@Bean
|
||||
Driver driver() {
|
||||
Driver driver = mock(Driver.class);
|
||||
when(driver.metrics()).thenThrow(ClientException.class);
|
||||
return driver;
|
||||
}
|
||||
@Test
|
||||
void connectionTimeout() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.setConnectionTimeout(Duration.ofMillis(500));
|
||||
assertThat(mapDriverConfig(properties).connectionTimeoutMillis()).isEqualTo(500);
|
||||
}
|
||||
|
||||
@Test
|
||||
void maxTransactionRetryTime() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.setMaxTransactionRetryTime(Duration.ofSeconds(2));
|
||||
assertThat(mapDriverConfig(properties)).extracting("retrySettings")
|
||||
.hasFieldOrPropertyWithValue("maxRetryTimeMs", 2000L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void authenticationShouldDefaultToNone() {
|
||||
assertThat(mapAuthToken(new Authentication())).isEqualTo(AuthTokens.none());
|
||||
}
|
||||
|
||||
@Test
|
||||
void authenticationWithUsernameShouldEnableBasicAuth() {
|
||||
Authentication authentication = new Authentication();
|
||||
authentication.setUsername("Farin");
|
||||
authentication.setPassword("Urlaub");
|
||||
assertThat(mapAuthToken(authentication)).isEqualTo(AuthTokens.basic("Farin", "Urlaub"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void authenticationWithUsernameAndRealmShouldEnableBasicAuth() {
|
||||
Authentication authentication = new Authentication();
|
||||
authentication.setUsername("Farin");
|
||||
authentication.setPassword("Urlaub");
|
||||
authentication.setRealm("Test Realm");
|
||||
assertThat(mapAuthToken(authentication)).isEqualTo(AuthTokens.basic("Farin", "Urlaub", "Test Realm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void authenticationWithKerberosTicketShouldEnableKerberos() {
|
||||
Authentication authentication = new Authentication();
|
||||
authentication.setKerberosTicket("AABBCCDDEE");
|
||||
assertThat(mapAuthToken(authentication)).isEqualTo(AuthTokens.kerberos("AABBCCDDEE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void authenticationWithBothUsernameAndKerberosShouldNotBeAllowed() {
|
||||
Authentication authentication = new Authentication();
|
||||
authentication.setUsername("Farin");
|
||||
authentication.setKerberosTicket("AABBCCDDEE");
|
||||
assertThatIllegalStateException().isThrownBy(() -> mapAuthToken(authentication))
|
||||
.withMessage("Cannot specify both username ('Farin') and kerberos ticket ('AABBCCDDEE')");
|
||||
}
|
||||
|
||||
@Test
|
||||
void poolWithMetricsEnabled() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getPool().setMetricsEnabled(true);
|
||||
assertThat(mapDriverConfig(properties).isMetricsEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void poolWithLogLeakedSessions() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getPool().setLogLeakedSessions(true);
|
||||
assertThat(mapDriverConfig(properties).logLeakedSessions()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void poolWithMaxConnectionPoolSize() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getPool().setMaxConnectionPoolSize(4711);
|
||||
assertThat(mapDriverConfig(properties).maxConnectionPoolSize()).isEqualTo(4711);
|
||||
}
|
||||
|
||||
@Test
|
||||
void poolWithIdleTimeBeforeConnectionTest() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getPool().setIdleTimeBeforeConnectionTest(Duration.ofSeconds(23));
|
||||
assertThat(mapDriverConfig(properties).idleTimeBeforeConnectionTest()).isEqualTo(23000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void poolWithMaxConnectionLifetime() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getPool().setMaxConnectionLifetime(Duration.ofSeconds(30));
|
||||
assertThat(mapDriverConfig(properties).maxConnectionLifetimeMillis()).isEqualTo(30000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void poolWithConnectionAcquisitionTimeout() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getPool().setConnectionAcquisitionTimeout(Duration.ofSeconds(5));
|
||||
assertThat(mapDriverConfig(properties).connectionAcquisitionTimeoutMillis()).isEqualTo(5000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityWithEncrypted() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getSecurity().setEncrypted(true);
|
||||
assertThat(mapDriverConfig(properties).encrypted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityWithTrustSignedCertificates() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);
|
||||
assertThat(mapDriverConfig(properties).trustStrategy().strategy())
|
||||
.isEqualTo(Config.TrustStrategy.Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityWithTrustAllCertificates() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_ALL_CERTIFICATES);
|
||||
assertThat(mapDriverConfig(properties).trustStrategy().strategy())
|
||||
.isEqualTo(Config.TrustStrategy.Strategy.TRUST_ALL_CERTIFICATES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityWitHostnameVerificationEnabled() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_ALL_CERTIFICATES);
|
||||
properties.getSecurity().setHostnameVerificationEnabled(true);
|
||||
assertThat(mapDriverConfig(properties).trustStrategy().isHostnameVerificationEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityWithCustomCertificates(@TempDir File directory) throws IOException {
|
||||
File certFile = new File(directory, "neo4j-driver.cert");
|
||||
assertThat(certFile.createNewFile());
|
||||
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES);
|
||||
properties.getSecurity().setCertFile(certFile);
|
||||
Config.TrustStrategy trustStrategy = mapDriverConfig(properties).trustStrategy();
|
||||
assertThat(trustStrategy.strategy())
|
||||
.isEqualTo(Config.TrustStrategy.Strategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES);
|
||||
assertThat(trustStrategy.certFile()).isEqualTo(certFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityWithCustomCertificatesShouldFailWithoutCertificate() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES);
|
||||
assertThatExceptionOfType(InvalidConfigurationPropertyValueException.class)
|
||||
.isThrownBy(() -> mapDriverConfig(properties)).withMessage(
|
||||
"Property spring.neo4j.security.trust-strategy with value 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES' is invalid: Configured trust strategy requires a certificate file.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void securityWithTrustSystemCertificates() {
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
properties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);
|
||||
assertThat(mapDriverConfig(properties).trustStrategy().strategy())
|
||||
.isEqualTo(Config.TrustStrategy.Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverConfigShouldBeConfiguredToUseUseSpringJclLogging() {
|
||||
assertThat(mapDriverConfig(new Neo4jProperties()).logging()).isNotNull()
|
||||
.isInstanceOf(Neo4jSpringJclLogging.class);
|
||||
}
|
||||
|
||||
private AuthToken mapAuthToken(Authentication authentication) {
|
||||
return new Neo4jAutoConfiguration().mapAuthToken(authentication);
|
||||
}
|
||||
|
||||
private Config mapDriverConfig(Neo4jProperties properties, ConfigBuilderCustomizer... customizers) {
|
||||
return new Neo4jAutoConfiguration().mapDriverConfig(properties, Arrays.asList(customizers));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,35 +16,62 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.neo4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.neo4j.driver.AuthTokens;
|
||||
import org.neo4j.driver.Config;
|
||||
import org.neo4j.driver.internal.retry.RetrySettings;
|
||||
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.Authentication;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.DriverSettings;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.PoolSettings;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.TrustSettings;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.TrustSettings.Strategy;
|
||||
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties.Pool;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link Neo4jProperties}.
|
||||
*
|
||||
* @author Michael J. Simons
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class Neo4jPropertiesTests {
|
||||
|
||||
@Test
|
||||
void poolSettingsHaveConsistentDefaults() {
|
||||
Config defaultConfig = Config.defaultConfig();
|
||||
Pool pool = new Neo4jProperties().getPool();
|
||||
assertThat(pool.isMetricsEnabled()).isEqualTo(defaultConfig.isMetricsEnabled());
|
||||
assertThat(pool.isLogLeakedSessions()).isEqualTo(defaultConfig.logLeakedSessions());
|
||||
assertThat(pool.getMaxConnectionPoolSize()).isEqualTo(defaultConfig.maxConnectionPoolSize());
|
||||
assertDuration(pool.getIdleTimeBeforeConnectionTest(), defaultConfig.idleTimeBeforeConnectionTest());
|
||||
assertDuration(pool.getMaxConnectionLifetime(), defaultConfig.maxConnectionLifetimeMillis());
|
||||
assertDuration(pool.getConnectionAcquisitionTimeout(), defaultConfig.connectionAcquisitionTimeoutMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
void securitySettingsHaveConsistentDefaults() {
|
||||
Config defaultConfig = Config.defaultConfig();
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
assertThat(properties.getSecurity().isEncrypted()).isEqualTo(defaultConfig.encrypted());
|
||||
assertThat(properties.getSecurity().getTrustStrategy().name())
|
||||
.isEqualTo(defaultConfig.trustStrategy().strategy().name());
|
||||
assertThat(properties.getSecurity().isHostnameVerificationEnabled())
|
||||
.isEqualTo(defaultConfig.trustStrategy().isHostnameVerificationEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverSettingsHaveConsistentDefaults() {
|
||||
Config defaultConfig = Config.defaultConfig();
|
||||
Neo4jProperties properties = new Neo4jProperties();
|
||||
assertDuration(properties.getConnectionTimeout(), defaultConfig.connectionTimeoutMillis());
|
||||
assertDuration(properties.getMaxTransactionRetryTime(), RetrySettings.DEFAULT.maxRetryTimeMs());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAssumeDefaultValuesForUrl() {
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
assertThat(driverProperties.getUri()).isEqualTo(URI.create("bolt://localhost:7687"));
|
||||
}
|
||||
|
||||
private static void assertDuration(Duration duration, long expectedValueInMillis) {
|
||||
if (expectedValueInMillis == org.neo4j.driver.internal.async.pool.PoolSettings.NOT_CONFIGURED) {
|
||||
assertThat(duration).isNull();
|
||||
@@ -54,266 +81,4 @@ class Neo4jPropertiesTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAllowEmptyListOfURIs() {
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
assertThat(driverProperties.getAuthentication()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noAuthenticationShouldWork() {
|
||||
Authentication authentication = new Authentication();
|
||||
assertThat(Neo4jAutoConfiguration.asAuthToken(authentication)).isEqualTo(AuthTokens.none());
|
||||
}
|
||||
|
||||
@Test
|
||||
void basicAuthShouldWork() {
|
||||
Authentication authentication = new Authentication();
|
||||
authentication.setUsername("Farin");
|
||||
authentication.setPassword("Urlaub");
|
||||
|
||||
assertThat(Neo4jAutoConfiguration.asAuthToken(authentication)).isEqualTo(AuthTokens.basic("Farin", "Urlaub"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void basicAuthWithRealmShouldWork() {
|
||||
Authentication authentication = new Authentication();
|
||||
authentication.setUsername("Farin");
|
||||
authentication.setPassword("Urlaub");
|
||||
authentication.setRealm("Die Ärzte");
|
||||
|
||||
assertThat(Neo4jAutoConfiguration.asAuthToken(authentication))
|
||||
.isEqualTo(AuthTokens.basic("Farin", "Urlaub", "Die Ärzte"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void kerberosAuthShouldWork() {
|
||||
Authentication authentication = new Authentication();
|
||||
authentication.setKerberosTicket("AABBCCDDEE");
|
||||
|
||||
assertThat(Neo4jAutoConfiguration.asAuthToken(authentication)).isEqualTo(AuthTokens.kerberos("AABBCCDDEE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void ambiguousShouldNotBeAllowed() {
|
||||
Authentication authentication = new Authentication();
|
||||
authentication.setUsername("Farin");
|
||||
authentication.setKerberosTicket("AABBCCDDEE");
|
||||
|
||||
assertThatExceptionOfType(InvalidConfigurationPropertyValueException.class)
|
||||
.isThrownBy(() -> Neo4jAutoConfiguration.asAuthToken(authentication)).withMessage(
|
||||
"Property org.neo4j.driver.authentication with value 'username=Farin,kerberos-ticket=AABBCCDDEE' is invalid: Cannot specify both username and kerberos ticket.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void poolSettingsShouldDefaultToDriversValues() {
|
||||
Config defaultConfig = Config.defaultConfig();
|
||||
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
|
||||
PoolSettings poolSettings = driverProperties.getPool();
|
||||
assertThat(poolSettings.isLogLeakedSessions()).isEqualTo(defaultConfig.logLeakedSessions());
|
||||
assertThat(poolSettings.getMaxConnectionPoolSize()).isEqualTo(defaultConfig.maxConnectionPoolSize());
|
||||
assertDuration(poolSettings.getIdleTimeBeforeConnectionTest(), defaultConfig.idleTimeBeforeConnectionTest());
|
||||
assertDuration(poolSettings.getMaxConnectionLifetime(), defaultConfig.maxConnectionLifetimeMillis());
|
||||
assertDuration(poolSettings.getConnectionAcquisitionTimeout(),
|
||||
defaultConfig.connectionAcquisitionTimeoutMillis());
|
||||
assertThat(poolSettings.isMetricsEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void logLeakedSessionsSettingsShouldWork() {
|
||||
Neo4jProperties driverProperties;
|
||||
|
||||
driverProperties = new Neo4jProperties();
|
||||
driverProperties.getPool().setLogLeakedSessions(true);
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).logLeakedSessions()).isTrue();
|
||||
|
||||
driverProperties = new Neo4jProperties();
|
||||
driverProperties.getPool().setLogLeakedSessions(false);
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).logLeakedSessions()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void maxConnectionPoolSizeSettingsShouldWork() {
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
driverProperties.getPool().setMaxConnectionPoolSize(4711);
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).maxConnectionPoolSize()).isEqualTo(4711);
|
||||
}
|
||||
|
||||
@Test
|
||||
void idleTimeBeforeConnectionTestSettingsShouldWork() {
|
||||
Neo4jProperties driverProperties;
|
||||
|
||||
driverProperties = new Neo4jProperties();
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).idleTimeBeforeConnectionTest())
|
||||
.isEqualTo(-1);
|
||||
|
||||
driverProperties = new Neo4jProperties();
|
||||
driverProperties.getPool().setIdleTimeBeforeConnectionTest(Duration.ofSeconds(23));
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).idleTimeBeforeConnectionTest())
|
||||
.isEqualTo(23_000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void connectionAcquisitionTimeoutSettingsShouldWork() {
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
driverProperties.getPool().setConnectionAcquisitionTimeout(Duration.ofSeconds(23));
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).connectionAcquisitionTimeoutMillis())
|
||||
.isEqualTo(23_000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void enableMetricsShouldWork() {
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).isMetricsEnabled()).isFalse();
|
||||
|
||||
driverProperties.getPool().setMetricsEnabled(true);
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).isMetricsEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverSettingsShouldDefaultToDriversValues() {
|
||||
Config defaultConfig = Config.defaultConfig();
|
||||
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
|
||||
DriverSettings driverSettings = driverProperties.getConfig();
|
||||
assertThat(driverSettings.isEncrypted()).isEqualTo(defaultConfig.encrypted());
|
||||
assertThat(driverSettings.getTrustSettings().getStrategy().name())
|
||||
.isEqualTo(defaultConfig.trustStrategy().strategy().name());
|
||||
assertDuration(driverSettings.getConnectionTimeout(), defaultConfig.connectionTimeoutMillis());
|
||||
assertDuration(driverSettings.getMaxTransactionRetryTime(), RetrySettings.DEFAULT.maxRetryTimeMs());
|
||||
assertThat(driverSettings.getServerAddressResolverClass()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void encryptedSettingsShouldWork() {
|
||||
Neo4jProperties driverProperties;
|
||||
|
||||
driverProperties = new Neo4jProperties();
|
||||
driverProperties.getConfig().setEncrypted(true);
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).encrypted()).isTrue();
|
||||
|
||||
driverProperties = new Neo4jProperties();
|
||||
driverProperties.getConfig().setEncrypted(false);
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).encrypted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void trustSettingsShouldWork() {
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
TrustSettings trustSettings = new TrustSettings();
|
||||
trustSettings.setStrategy(Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);
|
||||
driverProperties.getConfig().setTrustSettings(trustSettings);
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).trustStrategy().strategy())
|
||||
.isEqualTo(Config.TrustStrategy.Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void connectionTimeoutSettingsShouldWork() {
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
driverProperties.getConfig().setConnectionTimeout(Duration.ofSeconds(23));
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).connectionTimeoutMillis()).isEqualTo(23_000);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("The internal driver has no means of retrieving that value back again")
|
||||
void maxTransactionRetryTimeSettingsShouldWork() {
|
||||
DriverSettings driverSettings = new DriverSettings();
|
||||
driverSettings.setMaxTransactionRetryTime(Duration.ofSeconds(23));
|
||||
}
|
||||
|
||||
@Test
|
||||
void serverAddressResolverClassSettingsShouldWork() {
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
driverProperties.getConfig().setServerAddressResolverClass(TestServerAddressResolver.class);
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).resolver()).isNotNull()
|
||||
.isInstanceOf(TestServerAddressResolver.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseSpringJclLogging() {
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
assertThat(Neo4jAutoConfiguration.asDriverConfig(driverProperties).logging()).isNotNull()
|
||||
.isInstanceOf(Neo4jSpringJclLogging.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void trustAllCertificatesShouldWork() {
|
||||
TrustSettings settings = new TrustSettings();
|
||||
settings.setStrategy(Strategy.TRUST_ALL_CERTIFICATES);
|
||||
|
||||
assertThat(Neo4jAutoConfiguration.toInternalRepresentation(settings).strategy())
|
||||
.isEqualTo(Config.TrustStrategy.Strategy.TRUST_ALL_CERTIFICATES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldEnableHostnameVerification() {
|
||||
TrustSettings settings = new TrustSettings();
|
||||
settings.setStrategy(Strategy.TRUST_ALL_CERTIFICATES);
|
||||
settings.setHostnameVerificationEnabled(true);
|
||||
|
||||
assertThat(Neo4jAutoConfiguration.toInternalRepresentation(settings).isHostnameVerificationEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void trustSystemCertificatesShouldWork() {
|
||||
|
||||
TrustSettings settings = new TrustSettings();
|
||||
settings.setStrategy(Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);
|
||||
|
||||
assertThat(Neo4jAutoConfiguration.toInternalRepresentation(settings).strategy())
|
||||
.isEqualTo(Config.TrustStrategy.Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void trustCustomCertificatesShouldWork() throws IOException {
|
||||
File certFile = File.createTempFile("neo4j-driver", ".cert");
|
||||
|
||||
TrustSettings settings = new TrustSettings();
|
||||
settings.setStrategy(Strategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES);
|
||||
settings.setCertFile(certFile);
|
||||
|
||||
Config.TrustStrategy trustStrategy = Neo4jAutoConfiguration.toInternalRepresentation(settings);
|
||||
assertThat(trustStrategy.strategy())
|
||||
.isEqualTo(Config.TrustStrategy.Strategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES);
|
||||
assertThat(trustStrategy.certFile()).isEqualTo(certFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
void trustCustomCertificatesShouldFailWithoutCertificate() {
|
||||
TrustSettings settings = new TrustSettings();
|
||||
settings.setStrategy(Strategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES);
|
||||
|
||||
assertThatExceptionOfType(InvalidConfigurationPropertyValueException.class)
|
||||
.isThrownBy(() -> Neo4jAutoConfiguration.toInternalRepresentation(settings)).withMessage(
|
||||
"Property org.neo4j.driver.config.trust-settings with value 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES' is invalid: Configured trust strategy requires a certificate file.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAssumeDefaultValuesForUrl() {
|
||||
Neo4jProperties driverProperties = new Neo4jProperties();
|
||||
assertThat(driverProperties.getUri()).isEqualTo(URI.create("bolt://localhost:7687"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "bolt", "Bolt", "neo4j", "Neo4J" })
|
||||
void shouldDetectSimpleSchemes(String aSimpleScheme) {
|
||||
assertThat(Neo4jAutoConfiguration.isSimpleScheme(aSimpleScheme)).isTrue();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "bolt+s", "Bolt+ssc", "neo4j+s", "Neo4J+ssc" })
|
||||
void shouldDetectAdvancedSchemes(String anAdvancedScheme) {
|
||||
assertThat(Neo4jAutoConfiguration.isSimpleScheme(anAdvancedScheme)).isFalse();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "bolt+routing", "bolt+x", "neo4j+wth" })
|
||||
void shouldFailEarlyOnInvalidSchemes(String invalidScheme) {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> Neo4jAutoConfiguration.isSimpleScheme(invalidScheme))
|
||||
.withMessage("'%s' is not a supported scheme.", invalidScheme);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1170,7 +1170,7 @@ bom {
|
||||
]
|
||||
}
|
||||
}
|
||||
library("Neo4j", "4.1.0") {
|
||||
library("Neo4j", "4.1.1") {
|
||||
group("org.neo4j.driver") {
|
||||
modules = [
|
||||
"neo4j-java-driver"
|
||||
|
||||
@@ -4495,20 +4495,20 @@ Spring Boot offers several conveniences for working with Neo4j, including the `s
|
||||
|
||||
[[boot-features-connecting-to-neo4j]]
|
||||
==== Connecting to a Neo4j Database
|
||||
To access a Neo4j server, you can inject an auto-configured `org.neo4j.ogm.session.Session`.
|
||||
To access a Neo4j server, you can inject an auto-configured `org.neo4j.driver.Driver`.
|
||||
By default, the instance tries to connect to a Neo4j server at `localhost:7687` using the Bolt protocol.
|
||||
The following example shows how to inject a Neo4j `Session`:
|
||||
The following example shows how to inject a Neo4j `Driver` that gives you access, amongst other things, to a `Session`:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Component
|
||||
public class MyBean {
|
||||
|
||||
private final Session session;
|
||||
private final Driver driver;
|
||||
|
||||
@Autowired
|
||||
public MyBean(Session session) {
|
||||
this.session = session;
|
||||
public MyBean(Driver driver) {
|
||||
this.driver = driver;
|
||||
}
|
||||
|
||||
// ...
|
||||
@@ -4516,16 +4516,19 @@ The following example shows how to inject a Neo4j `Session`:
|
||||
}
|
||||
----
|
||||
|
||||
You can configure the uri and credentials to use by setting the `spring.data.neo4j.*` properties, as shown in the following example:
|
||||
You can configure various aspects of the driver using `spring.neo4j.*` properties.
|
||||
The following example shows how to configure the uri and credentials to use:
|
||||
|
||||
[source,properties,indent=0,configprops]
|
||||
----
|
||||
spring.data.neo4j.uri=bolt://my-server:7687
|
||||
spring.data.neo4j.username=neo4j
|
||||
spring.data.neo4j.password=secret
|
||||
spring.neo4j.uri=bolt://my-server:7687
|
||||
spring.neo4j.authentication.username=neo4j
|
||||
spring.neo4j.authentication.password=secret
|
||||
----
|
||||
|
||||
You can take full control over the session creation by adding either an `org.neo4j.ogm.config.Configuration` bean or an `org.neo4j.ogm.session.SessionFactory` bean.
|
||||
The auto-configured `Driver` is created using `ConfigBuilder`.
|
||||
To fine-tune its configuration, declare one or more `ConfigBuilderCustomizer` beans.
|
||||
Each will be called in order with the `ConfigBuilder` that is used to build the `Driver`.
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user