I am trying to write a sample in order to learn couchbase. I am trying to use it with spring boot and it’s crud repositories .
So I have downloaded latest docker image but the point is: i could not find the password of the bucket. The couchbase console allows only user creation but in spring, there is no equivalent of this usage like a username/password. It allows only bucketName and password which does not seem compatible with couchbase 5.
Am I missing anything here or is spring not compatible with couchbase 5? If spring is not compatible, which version of couchbase is ok?
Thx
Spring Data Couchbase is compatible with Couchbase Server 5.0. You can achieve the same auth as 4.x by creating a user with the same name as the bucket, then just use that bucket name and password from Spring Data if it's prior to 3.0/Kay.
The docs should cover this and if there's anything confusing there, please click the "feedback" button and offer what could be improved!
https://developer.couchbase.com/documentation/server/5.0/security/security-authorization.html https://developer.couchbase.com/documentation/server/5.0/security/concepts-rba-for-apps.html https://developer.couchbase.com/documentation/server/5.0/security/security-resources-under-access-control.html
I faced the same issue. I started debugging by getting into AbstractCouchbaseConfiguration and there i found
public abstract class AbstractCouchbaseConfiguration extends AbstractCouchbaseDataConfiguration implements CouchbaseConfigurer { ....//some other configuration @Override @Bean(name = BeanNames.COUCHBASE_CLUSTER_INFO) public ClusterInfo couchbaseClusterInfo() throws Exception { return couchbaseCluster().clusterManager(getBucketName(), getBucketPassword()).info(); }
What i did is created a bucket with the same name as of my couchbase user.
couchbase username : userdetail
couchbase password : ******
bucket name : userdetail
Couchbase driver supports connection to Couchbase 5 buckets using username/password. Problem is that spring-data-couchbase
is not developed fast enough to cover all the new features Couchbase introduces. So, we need to help Spring
to use a new bucket connection, doing it by overriding Couchbase cluster instantiation method of spring-data-couchbase
configuration base class - org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration
. This is the method we are looking at :
@Override @Bean(name = BeanNames.COUCHBASE_CLUSTER_INFO) public ClusterInfo couchbaseClusterInfo() throws Exception { return couchbaseCluster().clusterManager(getBucketName(), getBucketPassword()).info(); }
as we can see, it's not using username, just bucket and password, so in our configuration we will override it as following :
@Override @Bean(name = BeanNames.COUCHBASE_CLUSTER_INFO) public ClusterInfo couchbaseClusterInfo() throws Exception { return couchbaseCluster().authenticate(couchbaseUsername, couchbasePassword).clusterManager().info(); }
that's it. Here is the full code of my spring-data-couchbase
configuration :
import com.couchbase.client.java.Bucket; import com.couchbase.client.java.cluster.ClusterInfo; import com.couchbase.client.java.env.CouchbaseEnvironment; import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; import org.springframework.data.couchbase.config.BeanNames; import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; import javax.inject.Inject; import java.security.KeyStore; import java.util.List; /** * @author by avoinovan */ @Configuration @EnableCouchbaseRepositories public class ModelConfig extends AbstractCouchbaseConfiguration { private final static int DEFAULT_HTTP_PORT = 8091; private final static int DEFAULT_HTTP_SSL_PORT = 18091; private final static int DEFAULT_CARRIER_PORT = 11210; private final static int DEFAULT_CARRIER_SSL_PORT = 11207; private final static long DEFAULT_KEEP_ALIVE_INTERVAL = 30000; private final static int DEFAULT_SOCKET_CONNECT_TIMEOUT_MS = 5000; private final static long DEFAULT_CONNECT_TIMEOUT_MS = 5000; private final static long DEFAULT_MANAGEMENT_TIMEOUT_MS = 75000; private final static long DEFAULT_DISCONNECT_TIMEOUT_MS = 25000; private final static String PROPERTY_KEEP_ALIVE_INTERVAL_MS = "couchbase.keep_alive_interval_ms"; private final static String PROPERTY_SOCKET_CONNECT_TIMEOUT_MS = "couchbase.socket_connect_timeout_ms"; private final static String PROPERTY_CONNECT_TIMEOUT_MS = "couchbase.connect_timeout_ms"; private final static String PROPERTY_MANAGEMENT_TIMEOUT_MS = "couchbase.management_timeout_ms"; private final static String PROPERTY_DISCONNECT_TIMEOUT_MS = "couchbase.disconnect_timeout_ms"; private final static String PROPERTY_SSL_ENABLED = "couchbase.ssl.enabled"; private final static String PROPERTY_SSL_KEYSTORE_FILE = "couchbase.ssl.keystore.file"; private final static String PROPERTY_SSL_KEYSTORE_PASSWORD = "couchbase.ssl.keystore.password"; private final static String PROPERTY_SSL_TRUSTSTORE_FILE = "couchbase.ssl.truststore.file"; private final static String PROPERTY_SSL_TRUSTSTORE_PASSWORD = "couchbase.ssl.truststore.password"; private final static String PROPERTY_BOOTSTRAP_HTTP_ENABLED = "couchbase.bootstrap.http.enabled"; private final static String PROPERTY_BOOTSTRAP_HTTP_PORT = "couchbase.bootstrap.http.port"; private final static String PROPERTY_BOOTSTRAP_HTTP_SSL_PORT = "couchbase.bootstrap.http.ssl.port"; private final static String PROPERTY_BOOTSTRAP_CARRIER_ENABLED = "couchbase.bootstrap.carrier.enabled"; private final static String PROPERTY_BOOTSTRAP_CARRIER_PORT = "couchbase.bootstrap.carrier.port"; private final static String PROPERTY_BOOTSTRAP_CARRIER_SSL_PORT = "couchbase.bootstrap.carrier.ssl.port"; @Value("#{'${spring.couchbase.bootstrap-hosts}'.split(',')}") private List<String> couchbaseBootstrapHosts; @Value("${spring.couchbase.bucket.name}") private String bucketName; @Value("${spring.couchbase.password}") private String couchbasePassword; @Value("${spring.couchbase.username}") private String couchbaseUsername; private final Environment environment; private final ResourceLoader resourceLoader; @Inject public ModelConfig(final Environment environment, final ResourceLoader resourceLoader) { this.environment = environment; this.resourceLoader = resourceLoader; } protected List<String> getBootstrapHosts() { return couchbaseBootstrapHosts; } protected String getBucketName() { return bucketName; } protected String getBucketPassword() { return couchbasePassword; } protected CouchbaseEnvironment getEnvironment() { return DefaultCouchbaseEnvironment.builder() .keepAliveInterval(environment.getProperty(PROPERTY_KEEP_ALIVE_INTERVAL_MS, Long.class, DEFAULT_KEEP_ALIVE_INTERVAL)) // timeout settings .socketConnectTimeout(environment.getProperty(PROPERTY_SOCKET_CONNECT_TIMEOUT_MS, Integer.class, DEFAULT_SOCKET_CONNECT_TIMEOUT_MS)) .connectTimeout(environment.getProperty(PROPERTY_CONNECT_TIMEOUT_MS, Long.class, DEFAULT_CONNECT_TIMEOUT_MS)) .managementTimeout(environment.getProperty(PROPERTY_MANAGEMENT_TIMEOUT_MS, Long.class, DEFAULT_MANAGEMENT_TIMEOUT_MS)) .disconnectTimeout(environment.getProperty(PROPERTY_DISCONNECT_TIMEOUT_MS, Long.class, DEFAULT_DISCONNECT_TIMEOUT_MS)) // port and ssl .sslEnabled(environment.getProperty(PROPERTY_SSL_ENABLED, Boolean.class, false)) .bootstrapHttpEnabled(environment.getProperty(PROPERTY_BOOTSTRAP_HTTP_ENABLED, Boolean.class, Boolean.TRUE)) .bootstrapHttpDirectPort(environment.getProperty(PROPERTY_BOOTSTRAP_HTTP_PORT, Integer.class, DEFAULT_HTTP_PORT)) .bootstrapHttpSslPort(environment.getProperty(PROPERTY_BOOTSTRAP_HTTP_SSL_PORT, Integer.class, DEFAULT_HTTP_SSL_PORT)) .bootstrapCarrierEnabled(environment.getProperty(PROPERTY_BOOTSTRAP_CARRIER_ENABLED, Boolean.class, Boolean.TRUE)) .bootstrapCarrierDirectPort(environment.getProperty(PROPERTY_BOOTSTRAP_CARRIER_PORT, Integer.class, DEFAULT_CARRIER_PORT)) .bootstrapCarrierSslPort(environment.getProperty(PROPERTY_BOOTSTRAP_CARRIER_SSL_PORT, Integer.class, DEFAULT_CARRIER_SSL_PORT)) // keystore and trust store .sslKeystore(createKeyStore(environment, resourceLoader)) .sslTruststore(createTrustStore(environment, resourceLoader)) .build(); } @Override @Bean(name = BeanNames.COUCHBASE_CLUSTER_INFO) public ClusterInfo couchbaseClusterInfo() throws Exception { return couchbaseCluster().authenticate(couchbaseUsername, couchbasePassword).clusterManager().info(); } /** * Return the {@link Bucket} instance to connect to. * * @throws Exception on Bean construction failure. */ @Override @Bean(destroyMethod = "close", name = BeanNames.COUCHBASE_BUCKET) public Bucket couchbaseClient() throws Exception { //@Bean method can use another @Bean method in the same @Configuration by directly invoking it return couchbaseCluster().openBucket(getBucketName()); } private KeyStore createKeyStore(final Environment environment, final ResourceLoader resourceLoader) { return loadKeyStore(environment, resourceLoader, PROPERTY_SSL_KEYSTORE_FILE, PROPERTY_SSL_KEYSTORE_PASSWORD); } private KeyStore createTrustStore(final Environment environment, final ResourceLoader resourceLoader) { return loadKeyStore(environment, resourceLoader, PROPERTY_SSL_TRUSTSTORE_FILE, PROPERTY_SSL_TRUSTSTORE_PASSWORD); } private KeyStore loadKeyStore(final Environment environment, final ResourceLoader resourceLoader, final String fileProperty, final String passwordProperty) { String file = environment.getProperty(fileProperty); String password = environment.getProperty(passwordProperty); if (file != null) { Resource resource = resourceLoader.getResource(file); if (resource != null) { try { KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(resource.getInputStream(), password == null ? null : password.toCharArray()); return keyStore; } catch (final Exception e) { throw new RuntimeException(e); } } } return null; } }