Polish "Add support for using an AuthTokenManager with Neo4j"

See gh-36650
pull/36693/head
Andy Wilkinson 1 year ago
parent 1f0a3901b2
commit 77e382ec64

@ -64,19 +64,20 @@ public class Neo4jAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(Neo4jConnectionDetails.class) @ConditionalOnMissingBean(Neo4jConnectionDetails.class)
PropertiesNeo4jConnectionDetails neo4jConnectionDetails(Neo4jProperties properties) { PropertiesNeo4jConnectionDetails neo4jConnectionDetails(Neo4jProperties properties,
return new PropertiesNeo4jConnectionDetails(properties); ObjectProvider<AuthTokenManager> authTokenManager) {
return new PropertiesNeo4jConnectionDetails(properties, authTokenManager.getIfUnique());
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public Driver neo4jDriver(Neo4jProperties properties, Environment environment, public Driver neo4jDriver(Neo4jProperties properties, Environment environment,
Neo4jConnectionDetails connectionDetails, ObjectProvider<ConfigBuilderCustomizer> configBuilderCustomizers, Neo4jConnectionDetails connectionDetails,
ObjectProvider<AuthTokenManager> authTokenManagers) { ObjectProvider<ConfigBuilderCustomizer> configBuilderCustomizers) {
Config config = mapDriverConfig(properties, connectionDetails, Config config = mapDriverConfig(properties, connectionDetails,
configBuilderCustomizers.orderedStream().toList()); configBuilderCustomizers.orderedStream().toList());
AuthTokenManager authTokenManager = authTokenManagers.getIfUnique(); AuthTokenManager authTokenManager = connectionDetails.getAuthTokenManager();
if (authTokenManager != null) { if (authTokenManager != null) {
return GraphDatabase.driver(connectionDetails.getUri(), authTokenManager, config); return GraphDatabase.driver(connectionDetails.getUri(), authTokenManager, config);
} }
@ -187,8 +188,11 @@ public class Neo4jAutoConfiguration {
private final Neo4jProperties properties; private final Neo4jProperties properties;
PropertiesNeo4jConnectionDetails(Neo4jProperties properties) { private final AuthTokenManager authTokenManager;
PropertiesNeo4jConnectionDetails(Neo4jProperties properties, AuthTokenManager authTokenManager) {
this.properties = properties; this.properties = properties;
this.authTokenManager = authTokenManager;
} }
@Override @Override
@ -217,6 +221,11 @@ public class Neo4jAutoConfiguration {
return AuthTokens.none(); return AuthTokens.none();
} }
@Override
public AuthTokenManager getAuthTokenManager() {
return this.authTokenManager;
}
} }
} }

@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.neo4j;
import java.net.URI; import java.net.URI;
import org.neo4j.driver.AuthToken; import org.neo4j.driver.AuthToken;
import org.neo4j.driver.AuthTokenManager;
import org.neo4j.driver.AuthTokens; import org.neo4j.driver.AuthTokens;
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails; import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
@ -49,4 +50,14 @@ public interface Neo4jConnectionDetails extends ConnectionDetails {
return AuthTokens.none(); return AuthTokens.none();
} }
/**
* Returns the {@link AuthTokenManager} to use for authentication. Defaults to
* {@code null} in which case the {@link #getAuthToken() auth token} should be used.
* @return the auth token manager
* @since 3.2.0
*/
default AuthTokenManager getAuthTokenManager() {
return null;
}
} }

@ -16,10 +16,12 @@
package org.springframework.boot.autoconfigure.neo4j; package org.springframework.boot.autoconfigure.neo4j;
import java.net.URI;
import java.time.Duration; import java.time.Duration;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.neo4j.driver.AuthToken;
import org.neo4j.driver.AuthTokenManager; import org.neo4j.driver.AuthTokenManager;
import org.neo4j.driver.AuthTokenManagers; import org.neo4j.driver.AuthTokenManagers;
import org.neo4j.driver.AuthTokens; import org.neo4j.driver.AuthTokens;
@ -124,4 +126,58 @@ class Neo4jAutoConfigurationIntegrationTests {
} }
@SpringBootTest
@Nested
class DriverWithCustomConnectionDetailsIgnoresAuthTokenManager {
@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("wrongagain", "stillwrong")
.expiringAt(System.currentTimeMillis() + 5_000));
}
@Bean
Neo4jConnectionDetails connectionDetails() {
return new Neo4jConnectionDetails() {
@Override
public URI getUri() {
return URI.create(neo4jServer.getBoltUrl());
}
@Override
public AuthToken getAuthToken() {
return AuthTokens.basic("neo4j", neo4jServer.getAdminPassword());
}
};
}
}
}
} }

@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.params.provider.ValueSource;
import org.neo4j.driver.AuthTokenManagers;
import org.neo4j.driver.AuthTokens; import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Config; import org.neo4j.driver.Config;
import org.neo4j.driver.Config.ConfigBuilder; import org.neo4j.driver.Config.ConfigBuilder;
@ -143,7 +144,7 @@ class Neo4jAutoConfigurationTests {
@Test @Test
void uriShouldDefaultToLocalhost() { void uriShouldDefaultToLocalhost() {
assertThat(new PropertiesNeo4jConnectionDetails(new Neo4jProperties()).getUri()) assertThat(new PropertiesNeo4jConnectionDetails(new Neo4jProperties(), null).getUri())
.isEqualTo(URI.create("bolt://localhost:7687")); .isEqualTo(URI.create("bolt://localhost:7687"));
} }
@ -152,12 +153,12 @@ class Neo4jAutoConfigurationTests {
URI customUri = URI.create("bolt://localhost:4242"); URI customUri = URI.create("bolt://localhost:4242");
Neo4jProperties properties = new Neo4jProperties(); Neo4jProperties properties = new Neo4jProperties();
properties.setUri(customUri); properties.setUri(customUri);
assertThat(new PropertiesNeo4jConnectionDetails(properties).getUri()).isEqualTo(customUri); assertThat(new PropertiesNeo4jConnectionDetails(properties, null).getUri()).isEqualTo(customUri);
} }
@Test @Test
void authenticationShouldDefaultToNone() { void authenticationShouldDefaultToNone() {
assertThat(new PropertiesNeo4jConnectionDetails(new Neo4jProperties()).getAuthToken()) assertThat(new PropertiesNeo4jConnectionDetails(new Neo4jProperties(), null).getAuthToken())
.isEqualTo(AuthTokens.none()); .isEqualTo(AuthTokens.none());
} }
@ -166,8 +167,9 @@ class Neo4jAutoConfigurationTests {
Neo4jProperties properties = new Neo4jProperties(); Neo4jProperties properties = new Neo4jProperties();
properties.getAuthentication().setUsername("Farin"); properties.getAuthentication().setUsername("Farin");
properties.getAuthentication().setPassword("Urlaub"); properties.getAuthentication().setPassword("Urlaub");
assertThat(new PropertiesNeo4jConnectionDetails(properties).getAuthToken()) PropertiesNeo4jConnectionDetails connectionDetails = new PropertiesNeo4jConnectionDetails(properties, null);
.isEqualTo(AuthTokens.basic("Farin", "Urlaub")); assertThat(connectionDetails.getAuthToken()).isEqualTo(AuthTokens.basic("Farin", "Urlaub"));
assertThat(connectionDetails.getAuthTokenManager()).isNull();
} }
@Test @Test
@ -177,8 +179,22 @@ class Neo4jAutoConfigurationTests {
authentication.setUsername("Farin"); authentication.setUsername("Farin");
authentication.setPassword("Urlaub"); authentication.setPassword("Urlaub");
authentication.setRealm("Test Realm"); authentication.setRealm("Test Realm");
assertThat(new PropertiesNeo4jConnectionDetails(properties).getAuthToken()) PropertiesNeo4jConnectionDetails connectionDetails = new PropertiesNeo4jConnectionDetails(properties, null);
.isEqualTo(AuthTokens.basic("Farin", "Urlaub", "Test Realm")); assertThat(connectionDetails.getAuthToken()).isEqualTo(AuthTokens.basic("Farin", "Urlaub", "Test Realm"));
assertThat(connectionDetails.getAuthTokenManager()).isNull();
}
@Test
void authenticationWithAuthTokenManagerAndUsernameShouldProvideAuthTokenManger() {
Neo4jProperties properties = new Neo4jProperties();
Authentication authentication = properties.getAuthentication();
authentication.setUsername("Farin");
authentication.setPassword("Urlaub");
authentication.setRealm("Test Realm");
assertThat(new PropertiesNeo4jConnectionDetails(properties,
AuthTokenManagers.expirationBased(
() -> AuthTokens.basic("username", "password").expiringAt(System.currentTimeMillis() + 5000)))
.getAuthTokenManager()).isNotNull();
} }
@Test @Test
@ -186,7 +202,7 @@ class Neo4jAutoConfigurationTests {
Neo4jProperties properties = new Neo4jProperties(); Neo4jProperties properties = new Neo4jProperties();
Authentication authentication = properties.getAuthentication(); Authentication authentication = properties.getAuthentication();
authentication.setKerberosTicket("AABBCCDDEE"); authentication.setKerberosTicket("AABBCCDDEE");
assertThat(new PropertiesNeo4jConnectionDetails(properties).getAuthToken()) assertThat(new PropertiesNeo4jConnectionDetails(properties, null).getAuthToken())
.isEqualTo(AuthTokens.kerberos("AABBCCDDEE")); .isEqualTo(AuthTokens.kerberos("AABBCCDDEE"));
} }
@ -197,7 +213,7 @@ class Neo4jAutoConfigurationTests {
authentication.setUsername("Farin"); authentication.setUsername("Farin");
authentication.setKerberosTicket("AABBCCDDEE"); authentication.setKerberosTicket("AABBCCDDEE");
assertThatIllegalStateException() assertThatIllegalStateException()
.isThrownBy(() -> new PropertiesNeo4jConnectionDetails(properties).getAuthToken()) .isThrownBy(() -> new PropertiesNeo4jConnectionDetails(properties, null).getAuthToken())
.withMessage("Cannot specify both username ('Farin') and kerberos ticket ('AABBCCDDEE')"); .withMessage("Cannot specify both username ('Farin') and kerberos ticket ('AABBCCDDEE')");
} }
@ -313,7 +329,7 @@ class Neo4jAutoConfigurationTests {
private Config mapDriverConfig(Neo4jProperties properties, ConfigBuilderCustomizer... customizers) { private Config mapDriverConfig(Neo4jProperties properties, ConfigBuilderCustomizer... customizers) {
return new Neo4jAutoConfiguration().mapDriverConfig(properties, return new Neo4jAutoConfiguration().mapDriverConfig(properties,
new PropertiesNeo4jConnectionDetails(properties), Arrays.asList(customizers)); new PropertiesNeo4jConnectionDetails(properties, null), Arrays.asList(customizers));
} }
} }

Loading…
Cancel
Save