Skip to content

Commit

Permalink
Add support for using an AuthTokenManager with Neo4j
Browse files Browse the repository at this point in the history
Neo4j Java driver introduced support for an `AuthTokenManager` that can
be used to define expiring tokens for authentication with a database.

This commit adds an `ObjectProvider<AuthTokenManager> authTokenManagers`
parameter to the corresponding auto configuration class. If the provider
resolves to a unique object, that `AuthTokenManager` will have precedence
over any static token.

See spring-projectsgh-36650
  • Loading branch information
michael-simons authored and wilkinsona committed Aug 2, 2023
1 parent e677eb7 commit d590d60
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 21 deletions.
Expand Up @@ -24,6 +24,7 @@
import java.util.concurrent.TimeUnit;

import org.neo4j.driver.AuthToken;
import org.neo4j.driver.AuthTokenManager;
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Config;
import org.neo4j.driver.Config.TrustStrategy;
Expand Down Expand Up @@ -70,11 +71,16 @@ PropertiesNeo4jConnectionDetails neo4jConnectionDetails(Neo4jProperties properti
@Bean
@ConditionalOnMissingBean
public Driver neo4jDriver(Neo4jProperties properties, Environment environment,
Neo4jConnectionDetails connectionDetails,
ObjectProvider<ConfigBuilderCustomizer> configBuilderCustomizers) {
AuthToken authToken = connectionDetails.getAuthToken();
Neo4jConnectionDetails connectionDetails, ObjectProvider<ConfigBuilderCustomizer> configBuilderCustomizers,
ObjectProvider<AuthTokenManager> authTokenManagers) {

Config config = mapDriverConfig(properties, connectionDetails,
configBuilderCustomizers.orderedStream().toList());
AuthTokenManager authTokenManager = authTokenManagers.getIfUnique();
if (authTokenManager != null) {
return GraphDatabase.driver(connectionDetails.getUri(), authTokenManager, config);
}
AuthToken authToken = connectionDetails.getAuthToken();
return GraphDatabase.driver(connectionDetails.getUri(), authToken, config);
}

Expand Down
Expand Up @@ -18,7 +18,11 @@

import java.time.Duration;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.neo4j.driver.AuthTokenManager;
import org.neo4j.driver.AuthTokenManagers;
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Result;
import org.neo4j.driver.Session;
Expand All @@ -31,6 +35,7 @@
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
Expand All @@ -43,7 +48,6 @@
* @author Michael J. Simons
* @author Stephane Nicoll
*/
@SpringBootTest
@Testcontainers(disabledWithoutDocker = true)
class Neo4jAutoConfigurationIntegrationTests {

Expand All @@ -52,28 +56,71 @@ class Neo4jAutoConfigurationIntegrationTests {
.withStartupAttempts(5)
.withStartupTimeout(Duration.ofMinutes(10));

@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4jServer::getBoltUrl);
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
registry.add("spring.neo4j.authentication.password", neo4jServer::getAdminPassword);
}
@SpringBootTest
@Nested
class DriverWithDefaultAuthToken {

@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4jServer::getBoltUrl);
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
registry.add("spring.neo4j.authentication.password", neo4jServer::getAdminPassword);
}

@Autowired
private Driver driver;

@Autowired
private Driver driver;
@Test
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();
tx.commit();
}
}

@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(Neo4jAutoConfiguration.class)
static class TestConfiguration {

@Test
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();
tx.commit();
}

}

@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(Neo4jAutoConfiguration.class)
static class TestConfiguration {
@SpringBootTest
@Nested
class DriverWithDynamicAuthToken {

@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4jServer::getBoltUrl);
registry.add("spring.neo4j.authentication.username", () -> "wrong");
registry.add("spring.neo4j.authentication.password", () -> "alsowrong");
}

@Autowired
private Driver driver;

@Test
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();
tx.commit();
}
}

@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(Neo4jAutoConfiguration.class)
static class TestConfiguration {

@Bean
AuthTokenManager authTokenManager() {
return AuthTokenManagers.expirationBased(() -> AuthTokens.basic("neo4j", neo4jServer.getAdminPassword())
.expiringAt(System.currentTimeMillis() + 5_000));
}

}

}

Expand Down

0 comments on commit d590d60

Please sign in to comment.