Support Couchbase authentication using client certificates
Closes gh-41520
This commit is contained in:
parent
d56dd741d0
commit
add3d87ea1
|
@ -16,8 +16,16 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.couchbase;
|
package org.springframework.boot.autoconfigure.couchbase;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
|
||||||
|
import com.couchbase.client.core.env.Authenticator;
|
||||||
|
import com.couchbase.client.core.env.CertificateAuthenticator;
|
||||||
|
import com.couchbase.client.core.env.PasswordAuthenticator;
|
||||||
import com.couchbase.client.java.Cluster;
|
import com.couchbase.client.java.Cluster;
|
||||||
import com.couchbase.client.java.ClusterOptions;
|
import com.couchbase.client.java.ClusterOptions;
|
||||||
import com.couchbase.client.java.codec.JacksonJsonSerializer;
|
import com.couchbase.client.java.codec.JacksonJsonSerializer;
|
||||||
|
@ -36,16 +44,22 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration.CouchbaseCondition;
|
import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration.CouchbaseCondition;
|
||||||
|
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Authentication.Jks;
|
||||||
|
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Authentication.Pem;
|
||||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Ssl;
|
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Ssl;
|
||||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Timeouts;
|
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Timeouts;
|
||||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.boot.io.ApplicationResourceLoader;
|
||||||
import org.springframework.boot.ssl.SslBundle;
|
import org.springframework.boot.ssl.SslBundle;
|
||||||
import org.springframework.boot.ssl.SslBundles;
|
import org.springframework.boot.ssl.SslBundles;
|
||||||
|
import org.springframework.boot.ssl.pem.PemSslStore;
|
||||||
|
import org.springframework.boot.ssl.pem.PemSslStoreDetails;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
@ -58,6 +72,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Moritz Halbritter
|
* @author Moritz Halbritter
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Scott Frederick
|
||||||
* @since 1.4.0
|
* @since 1.4.0
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration(after = JacksonAutoConfiguration.class)
|
@AutoConfiguration(after = JacksonAutoConfiguration.class)
|
||||||
|
@ -80,25 +95,51 @@ public class CouchbaseAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public ClusterEnvironment couchbaseClusterEnvironment(CouchbaseConnectionDetails connectionDetails,
|
public ClusterEnvironment couchbaseClusterEnvironment(
|
||||||
ObjectProvider<ClusterEnvironmentBuilderCustomizer> customizers, ObjectProvider<SslBundles> sslBundles) {
|
ObjectProvider<ClusterEnvironmentBuilderCustomizer> customizers, ObjectProvider<SslBundles> sslBundles) {
|
||||||
Builder builder = initializeEnvironmentBuilder(connectionDetails, sslBundles.getIfAvailable());
|
Builder builder = initializeEnvironmentBuilder(sslBundles.getIfAvailable());
|
||||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public Authenticator couchbaseAuthenticator(CouchbaseConnectionDetails connectionDetails) throws IOException {
|
||||||
|
if (connectionDetails.getUsername() != null && connectionDetails.getPassword() != null) {
|
||||||
|
return PasswordAuthenticator.create(connectionDetails.getUsername(), connectionDetails.getPassword());
|
||||||
|
}
|
||||||
|
Pem pem = this.properties.getAuthentication().getPem();
|
||||||
|
if (pem.getCertificates() != null) {
|
||||||
|
PemSslStoreDetails details = new PemSslStoreDetails(null, pem.getCertificates(), pem.getPrivateKey());
|
||||||
|
PemSslStore store = PemSslStore.load(details);
|
||||||
|
return CertificateAuthenticator.fromKey(store.privateKey(), pem.getPrivateKeyPassword(),
|
||||||
|
store.certificates());
|
||||||
|
}
|
||||||
|
Jks jks = this.properties.getAuthentication().getJks();
|
||||||
|
if (jks.getLocation() != null) {
|
||||||
|
Resource resource = new ApplicationResourceLoader().getResource(jks.getLocation());
|
||||||
|
String keystorePassword = jks.getPassword();
|
||||||
|
try (InputStream inputStream = resource.getInputStream()) {
|
||||||
|
KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
|
store.load(inputStream, (keystorePassword != null) ? keystorePassword.toCharArray() : null);
|
||||||
|
return CertificateAuthenticator.fromKeyStore(store, keystorePassword);
|
||||||
|
}
|
||||||
|
catch (GeneralSecurityException ex) {
|
||||||
|
throw new IllegalStateException("Error reading Couchbase certificate store", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Couchbase authentication requires username and password, or certificates");
|
||||||
|
}
|
||||||
|
|
||||||
@Bean(destroyMethod = "disconnect")
|
@Bean(destroyMethod = "disconnect")
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public Cluster couchbaseCluster(ClusterEnvironment couchbaseClusterEnvironment,
|
public Cluster couchbaseCluster(ClusterEnvironment couchbaseClusterEnvironment, Authenticator authenticator,
|
||||||
CouchbaseConnectionDetails connectionDetails) {
|
CouchbaseConnectionDetails connectionDetails) {
|
||||||
ClusterOptions options = ClusterOptions
|
ClusterOptions options = ClusterOptions.clusterOptions(authenticator).environment(couchbaseClusterEnvironment);
|
||||||
.clusterOptions(connectionDetails.getUsername(), connectionDetails.getPassword())
|
|
||||||
.environment(couchbaseClusterEnvironment);
|
|
||||||
return Cluster.connect(connectionDetails.getConnectionString(), options);
|
return Cluster.connect(connectionDetails.getConnectionString(), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClusterEnvironment.Builder initializeEnvironmentBuilder(CouchbaseConnectionDetails connectionDetails,
|
private ClusterEnvironment.Builder initializeEnvironmentBuilder(SslBundles sslBundles) {
|
||||||
SslBundles sslBundles) {
|
|
||||||
ClusterEnvironment.Builder builder = ClusterEnvironment.builder();
|
ClusterEnvironment.Builder builder = ClusterEnvironment.builder();
|
||||||
Timeouts timeouts = this.properties.getEnv().getTimeouts();
|
Timeouts timeouts = this.properties.getEnv().getTimeouts();
|
||||||
builder.timeoutConfig((config) -> config.kvTimeout(timeouts.getKeyValue())
|
builder.timeoutConfig((config) -> config.kvTimeout(timeouts.getKeyValue())
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Yulin Qin
|
* @author Yulin Qin
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
* @author Michael Nitschinger
|
* @author Michael Nitschinger
|
||||||
|
* @author Scott Frederick
|
||||||
* @since 1.4.0
|
* @since 1.4.0
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties(prefix = "spring.couchbase")
|
@ConfigurationProperties(prefix = "spring.couchbase")
|
||||||
|
@ -49,6 +50,8 @@ public class CouchbaseProperties {
|
||||||
*/
|
*/
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
private final Authentication authentication = new Authentication();
|
||||||
|
|
||||||
private final Env env = new Env();
|
private final Env env = new Env();
|
||||||
|
|
||||||
public String getConnectionString() {
|
public String getConnectionString() {
|
||||||
|
@ -75,10 +78,116 @@ public class CouchbaseProperties {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Authentication getAuthentication() {
|
||||||
|
return this.authentication;
|
||||||
|
}
|
||||||
|
|
||||||
public Env getEnv() {
|
public Env getEnv() {
|
||||||
return this.env;
|
return this.env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Authentication {
|
||||||
|
|
||||||
|
private final Pem pem = new Pem();
|
||||||
|
|
||||||
|
private final Jks jks = new Jks();
|
||||||
|
|
||||||
|
public Pem getPem() {
|
||||||
|
return this.pem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jks getJks() {
|
||||||
|
return this.jks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Pem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PEM-formatted certificates for certificate-based cluster authentication.
|
||||||
|
*/
|
||||||
|
private String certificates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PEM-formatted private key for certificate-based cluster authentication.
|
||||||
|
*/
|
||||||
|
private String privateKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private key password for certificate-based cluster authentication.
|
||||||
|
*/
|
||||||
|
private String privateKeyPassword;
|
||||||
|
|
||||||
|
public String getCertificates() {
|
||||||
|
return this.certificates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCertificates(String certificates) {
|
||||||
|
this.certificates = certificates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrivateKey() {
|
||||||
|
return this.privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrivateKey(String privateKey) {
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrivateKeyPassword() {
|
||||||
|
return this.privateKeyPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrivateKeyPassword(String privateKeyPassword) {
|
||||||
|
this.privateKeyPassword = privateKeyPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Jks {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java KeyStore location for certificate-based cluster authentication.
|
||||||
|
*/
|
||||||
|
private String location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java KeyStore password for certificate-based cluster authentication.
|
||||||
|
*/
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private key password for certificate-based cluster authentication.
|
||||||
|
*/
|
||||||
|
private String privateKeyPassword;
|
||||||
|
|
||||||
|
public String getLocation() {
|
||||||
|
return this.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocation(String location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return this.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrivateKeyPassword() {
|
||||||
|
return this.privateKeyPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrivateKeyPassword(String privateKeyPassword) {
|
||||||
|
this.privateKeyPassword = privateKeyPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static class Env {
|
public static class Env {
|
||||||
|
|
||||||
private final Io io = new Io();
|
private final Io io = new Io();
|
||||||
|
|
|
@ -21,7 +21,10 @@ import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import com.couchbase.client.core.env.Authenticator;
|
||||||
|
import com.couchbase.client.core.env.CertificateAuthenticator;
|
||||||
import com.couchbase.client.core.env.IoConfig;
|
import com.couchbase.client.core.env.IoConfig;
|
||||||
|
import com.couchbase.client.core.env.PasswordAuthenticator;
|
||||||
import com.couchbase.client.core.env.SecurityConfig;
|
import com.couchbase.client.core.env.SecurityConfig;
|
||||||
import com.couchbase.client.core.env.TimeoutConfig;
|
import com.couchbase.client.core.env.TimeoutConfig;
|
||||||
import com.couchbase.client.java.Cluster;
|
import com.couchbase.client.java.Cluster;
|
||||||
|
@ -54,6 +57,7 @@ import static org.mockito.Mockito.mock;
|
||||||
* @author Moritz Halbritter
|
* @author Moritz Halbritter
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Scott Frederick
|
||||||
*/
|
*/
|
||||||
class CouchbaseAutoConfigurationTests {
|
class CouchbaseAutoConfigurationTests {
|
||||||
|
|
||||||
|
@ -63,6 +67,7 @@ class CouchbaseAutoConfigurationTests {
|
||||||
@Test
|
@Test
|
||||||
void connectionStringIsRequired() {
|
void connectionStringIsRequired() {
|
||||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ClusterEnvironment.class)
|
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ClusterEnvironment.class)
|
||||||
|
.doesNotHaveBean(Authenticator.class)
|
||||||
.doesNotHaveBean(Cluster.class));
|
.doesNotHaveBean(Cluster.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +84,7 @@ class CouchbaseAutoConfigurationTests {
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
assertThat(context).hasSingleBean(ClusterEnvironment.class)
|
assertThat(context).hasSingleBean(ClusterEnvironment.class)
|
||||||
.hasSingleBean(Cluster.class)
|
.hasSingleBean(Cluster.class)
|
||||||
|
.hasSingleBean(PasswordAuthenticator.class)
|
||||||
.hasSingleBean(CouchbaseConnectionDetails.class)
|
.hasSingleBean(CouchbaseConnectionDetails.class)
|
||||||
.doesNotHaveBean(PropertiesCouchbaseConnectionDetails.class);
|
.doesNotHaveBean(PropertiesCouchbaseConnectionDetails.class);
|
||||||
Cluster cluster = context.getBean(Cluster.class);
|
Cluster cluster = context.getBean(Cluster.class);
|
||||||
|
@ -94,19 +100,24 @@ class CouchbaseAutoConfigurationTests {
|
||||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
||||||
.withPropertyValues("spring.couchbase.connection-string=localhost")
|
.withPropertyValues("spring.couchbase.connection-string=localhost")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
assertThat(context).hasSingleBean(ClusterEnvironment.class).hasSingleBean(Cluster.class);
|
assertThat(context).hasSingleBean(ClusterEnvironment.class)
|
||||||
|
.hasSingleBean(Authenticator.class)
|
||||||
|
.hasSingleBean(Cluster.class);
|
||||||
|
assertThat(context).doesNotHaveBean("couchbaseAuthenticator");
|
||||||
assertThat(context.getBean(Cluster.class))
|
assertThat(context.getBean(Cluster.class))
|
||||||
.isSameAs(context.getBean(CouchbaseTestConfiguration.class).couchbaseCluster());
|
.isSameAs(context.getBean(CouchbaseTestConfiguration.class).couchbaseCluster());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void connectionDetailsShouldOverrideProperties() {
|
void connectionDetailsOverridesProperties() {
|
||||||
this.contextRunner.withBean(CouchbaseConnectionDetails.class, this::couchbaseConnectionDetails)
|
this.contextRunner.withBean(CouchbaseConnectionDetails.class, this::couchbaseConnectionDetails)
|
||||||
.withPropertyValues("spring.couchbase.connection-string=localhost", "spring.couchbase.username=a-user",
|
.withPropertyValues("spring.couchbase.connection-string=localhost", "spring.couchbase.username=a-user",
|
||||||
"spring.couchbase.password=a-password")
|
"spring.couchbase.password=a-password")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
assertThat(context).hasSingleBean(ClusterEnvironment.class).hasSingleBean(Cluster.class);
|
assertThat(context).hasSingleBean(ClusterEnvironment.class)
|
||||||
|
.hasSingleBean(PasswordAuthenticator.class)
|
||||||
|
.hasSingleBean(Cluster.class);
|
||||||
Cluster cluster = context.getBean(Cluster.class);
|
Cluster cluster = context.getBean(Cluster.class);
|
||||||
assertThat(cluster.core()).extracting("connectionString.hosts")
|
assertThat(cluster.core()).extracting("connectionString.hosts")
|
||||||
.asInstanceOf(InstanceOfAssertFactories.LIST)
|
.asInstanceOf(InstanceOfAssertFactories.LIST)
|
||||||
|
@ -243,6 +254,41 @@ class CouchbaseAutoConfigurationTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void passwordAuthenticationWithUsernameAndPassword() {
|
||||||
|
this.contextRunner
|
||||||
|
.withPropertyValues("spring.couchbase.connection-string=localhost", "spring.couchbase.username=user",
|
||||||
|
"spring.couchbase.password=secret")
|
||||||
|
.run((context) -> assertThat(context).hasSingleBean(PasswordAuthenticator.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void certificateAuthenticationWithPemPrivateKeyAndCertificate() {
|
||||||
|
this.contextRunner.withPropertyValues("spring.couchbase.connection-string=localhost",
|
||||||
|
"spring.couchbase.env.ssl.enabled=true",
|
||||||
|
"spring.couchbase.authentication.pem.private-key=classpath:org/springframework/boot/autoconfigure/ssl/key2.pem",
|
||||||
|
"spring.couchbase.authentication.pem.certificates=classpath:org/springframework/boot/autoconfigure/ssl/key2.crt")
|
||||||
|
.run((context) -> assertThat(context).hasSingleBean(CertificateAuthenticator.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void certificateAuthenticationWithJavaKeyStore() {
|
||||||
|
this.contextRunner.withPropertyValues("spring.couchbase.connection-string=localhost",
|
||||||
|
"spring.couchbase.env.ssl.enabled=true",
|
||||||
|
"spring.couchbase.authentication.jks.location=classpath:org/springframework/boot/autoconfigure/ssl/keystore.jks",
|
||||||
|
"spring.couchbase.authentication.jks.password=secret")
|
||||||
|
.run((context) -> assertThat(context).hasSingleBean(CertificateAuthenticator.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void failsWithMissingAuthentication() {
|
||||||
|
this.contextRunner.withPropertyValues("spring.couchbase.connection-string=localhost").run((context) -> {
|
||||||
|
assertThat(context).hasFailed();
|
||||||
|
assertThat(context).getFailure()
|
||||||
|
.hasMessageContaining("Couchbase authentication requires username and password, or certificates");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private CouchbaseConnectionDetails couchbaseConnectionDetails() {
|
private CouchbaseConnectionDetails couchbaseConnectionDetails() {
|
||||||
return new CouchbaseConnectionDetails() {
|
return new CouchbaseConnectionDetails() {
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.couchbase;
|
package org.springframework.boot.autoconfigure.couchbase;
|
||||||
|
|
||||||
|
import com.couchbase.client.core.env.Authenticator;
|
||||||
import com.couchbase.client.java.Cluster;
|
import com.couchbase.client.java.Cluster;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -27,15 +28,23 @@ import static org.mockito.Mockito.mock;
|
||||||
* Test configuration for couchbase that mocks access.
|
* Test configuration for couchbase that mocks access.
|
||||||
*
|
*
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Scott Frederick
|
||||||
*/
|
*/
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
class CouchbaseTestConfiguration {
|
class CouchbaseTestConfiguration {
|
||||||
|
|
||||||
private final Cluster cluster = mock(Cluster.class);
|
private final Cluster cluster = mock(Cluster.class);
|
||||||
|
|
||||||
|
private final Authenticator authenticator = mock(Authenticator.class);
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
Cluster couchbaseCluster() {
|
Cluster couchbaseCluster() {
|
||||||
return this.cluster;
|
return this.cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Authenticator couchbaseAuth() {
|
||||||
|
return this.authenticator;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,7 +543,7 @@ There are `spring-boot-starter-data-couchbase` and `spring-boot-starter-data-cou
|
||||||
|
|
||||||
You can get a `Cluster` by adding the Couchbase SDK and some configuration.
|
You can get a `Cluster` by adding the Couchbase SDK and some configuration.
|
||||||
The `spring.couchbase.*` properties can be used to customize the connection.
|
The `spring.couchbase.*` properties can be used to customize the connection.
|
||||||
Generally, you provide the https://github.com/couchbaselabs/sdk-rfcs/blob/master/rfc/0011-connection-string.md[connection string], username, and password, as shown in the following example:
|
Generally, you provide the https://docs.couchbase.com/dotnet-sdk/current/howtos/managing-connections.html[connection string] and credentials for authentication. Basic authentication with username and password can be configured as shown in the following example:
|
||||||
|
|
||||||
[configprops,yaml]
|
[configprops,yaml]
|
||||||
----
|
----
|
||||||
|
@ -554,6 +554,39 @@ spring:
|
||||||
password: "secret"
|
password: "secret"
|
||||||
----
|
----
|
||||||
|
|
||||||
|
https://docs.couchbase.com/server/current/manage/manage-security/configure-client-certificates.html[Client certificates] can be used for authentication instead of username and password.
|
||||||
|
The location and password for a Java KeyStore containing client certificates can be configured as shown in the following example:
|
||||||
|
|
||||||
|
[configprops,yaml]
|
||||||
|
----
|
||||||
|
spring:
|
||||||
|
couchbase:
|
||||||
|
connection-string: "couchbase://192.168.1.123"
|
||||||
|
env:
|
||||||
|
ssl:
|
||||||
|
enabled: true
|
||||||
|
authentication:
|
||||||
|
jks:
|
||||||
|
location: "classpath:client.p12"
|
||||||
|
password: "secret"
|
||||||
|
----
|
||||||
|
|
||||||
|
PEM-encoded certificates and a private key can be configured as shown in the following example:
|
||||||
|
|
||||||
|
[configprops,yaml]
|
||||||
|
----
|
||||||
|
spring:
|
||||||
|
couchbase:
|
||||||
|
connection-string: "couchbase://192.168.1.123"
|
||||||
|
env:
|
||||||
|
ssl:
|
||||||
|
enabled: true
|
||||||
|
authentication:
|
||||||
|
pem:
|
||||||
|
certificates: "classpath:client.crt"
|
||||||
|
private-key: "classpath:client.key"
|
||||||
|
----
|
||||||
|
|
||||||
It is also possible to customize some of the `ClusterEnvironment` settings.
|
It is also possible to customize some of the `ClusterEnvironment` settings.
|
||||||
For instance, the following configuration changes the timeout to open a new `Bucket` and enables SSL support with a reference to a configured xref:features/ssl.adoc[SSL bundle]:
|
For instance, the following configuration changes the timeout to open a new `Bucket` and enables SSL support with a reference to a configured xref:features/ssl.adoc[SSL bundle]:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue