10

I try to setup a Mongo DB in Spring Boot project. I've set an uri in application.yml:

spring:
  data:
    mongodb:
      uri: mongodb://user:pass@localhost:27017/mydbname

But application fails to read data from repository with error:

Attempt to switch database target during SASL authentication.

Line where error occurs (kotlin):

val emails = emailRepository.findAllByStatus(READY_TO_SEND)

where

interface EmailRepository : MongoRepository<Email, String> {
    fun findAllByStatus(status: EmailStatus) : Collection<Email>
}

and

data class Email(
    @Id
    @get:JsonIgnore
    var id: String? = null,
    @get:NotNull
    val from: MailActor,
    @get:NotEmpty
    val to: Collection<MailActor>,
    @get:NotEmpty
    val subject: String,
    @get:NotEmpty
    val htmlText: String,
    val attachments: Collection<Attachment> = listOf(),
    val cc: Collection<MailActor> = listOf(),
    val bcc: Collection<MailActor> = listOf(),
    @get:JsonIgnore
    val status: EmailStatus = EmailStatus.READY_TO_SEND,
    @get:JsonIgnore
    val created: LocalDateTime = LocalDateTime.now(),
    @get:JsonIgnore
    val lastSendAttempt: LocalDateTime? = null,
)

The same error occurs with findAll and save operations on repository (and likely others too)

Stack trace:

Caused by: com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='user', source='user', password=<hidden>, mechanismProperties=<hidden>}
    at com.mongodb.internal.connection.SaslAuthenticator.wrapException(SaslAuthenticator.java:235) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator$1.run(SaslAuthenticator.java:80) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator$1.run(SaslAuthenticator.java:51) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator.doAsSubject(SaslAuthenticator.java:241) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator.authenticate(SaslAuthenticator.java:51) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnectionInitializer.authenticate(InternalStreamConnectionInitializer.java:168) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:63) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:144) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.UsageTrackingInternalConnection.open(UsageTrackingInternalConnection.java:51) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.open(DefaultConnectionPool.java:431) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:115) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:100) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.DefaultServer.getConnection(DefaultServer.java:92) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.binding.ClusterBinding$ClusterBindingConnectionSource.getConnection(ClusterBinding.java:119) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.client.internal.ClientSessionBinding$SessionBindingConnectionSource.getConnection(ClientSessionBinding.java:135) ~[mongodb-driver-sync-4.1.1.jar:na]
    at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:653) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:650) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.operation.OperationHelper.withReadConnectionSource(OperationHelper.java:582) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:650) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:78) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:178) ~[mongodb-driver-sync-4.1.1.jar:na]
    at com.mongodb.client.internal.MongoIterableImpl.execute(MongoIterableImpl.java:135) ~[mongodb-driver-sync-4.1.1.jar:na]
    at com.mongodb.client.internal.MongoIterableImpl.iterator(MongoIterableImpl.java:92) ~[mongodb-driver-sync-4.1.1.jar:na]
    at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:2790) ~[spring-data-mongodb-3.1.2.jar:3.1.2]
    ... 33 common frames omitted
Caused by: com.mongodb.MongoCommandException: Command failed with error 17 (ProtocolError): 'Attempt to switch database target during SASL authentication.' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "Attempt to switch database target during SASL authentication.", "code": 17, "codeName": "ProtocolError"}
    at com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:175) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:359) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:280) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.CommandHelper.sendAndReceive(CommandHelper.java:83) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.CommandHelper.executeCommand(CommandHelper.java:33) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator.sendSaslContinue(SaslAuthenticator.java:195) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator.access$200(SaslAuthenticator.java:43) ~[mongodb-driver-core-4.1.1.jar:na]
    at com.mongodb.internal.connection.SaslAuthenticator$1.run(SaslAuthenticator.java:69) ~[mongodb-driver-core-4.1.1.jar:na]
    ... 55 common frames omitted

I am able to connect to mongo via Intellij Idea client with the same credentials.

I run mongo db with docker-compose

version: '3.1'

services:
  mongodb:
    image: mongo
    container_name: my-service-mongo
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: user
      MONGO_INITDB_ROOT_PASSWORD: pass
      MONGO_INITDB_DATABASE: mydbname
    ports:
      - 27017:27017
    volumes:
      - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro

where mongo-init.js is

db.createUser(
    {
        user: "user",
        pwd: "pass",
        roles: [
            {
                role: "readWrite",
                db: "mydbname"
            }
        ]
    }
);

What is going on? The only place in the internet where I found this error message is... mongo source code 8].

Any help appreciated.

Lutosław
  • 606
  • 7
  • 24
  • Update to latest driver, use driver tutorial to reproduce the error with driver only, if it still happens report it to the driver using the published error reporting channels. – D. SM Jan 08 '21 at 17:17

7 Answers7

32
spring:
  data:
    mongodb:
      uri: mongodb://admin:admin@127.0.0.1:27017/dbname?authSource=admin

add authSource param

ChanningQiu
  • 351
  • 2
  • 7
2

If you:

  • Have multiple similar accounts (with same credentials), one in "admin" and the other in another database.
  • Intend to log in with the other account not in the "admin" database.
  • Have SASL enabled.

Then you may be affected by JAVA-4290, which is caused by speculative authentication only supporting the "admin" database, in mongodb-driver-core versions before 4.3.2. This resulted in the client successfully authenticating with the wrong account (the one in the admin database) via speculative authentication, only for MongoDB to trap the error when the SASL Continue message is sent. It does so with a Protocol Error, as you have observed.

As of Spring Boot 2.5.4, the version of mongodb-driver-core that ships with Spring Boot is only 4.2.3.

SP193
  • 156
  • 2
  • 5
0

It seems that it's a bug in mongo DB version

4.4.3-bionic

I've changed image in docker-compose to

mongo:3

and the error went away. Uh, so many hours....

Lutosław
  • 606
  • 7
  • 24
0

I faced the same issue . I was using the spring-boot-starter-parent 2.4.1 and it worked fine with the latest mongodb docker instance. But I had to connect to Bitnami mongo docker container which uses lower mongo and then the same error occurred. I downgraded the version to 2.3.7.RELEASE and then the expected behavior was obtained without errors.

This reason for the error for me was compatibility issue. Refer Spring data MongoDB Compatibility Matrix for viewing different versions and compatibility.

EDIT

I faced similar error in a different application. With the help of this stackoverflow post, Mongodb could not find user "user@database", I was able to understand the issue and solve it. Basically, you need to specify the authentication database properly. If not, by default the user will be checked in the database provided and not the authentication database. In my case I specified database A and my user was in admin db. So user admin was checked in database A.

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
sachin
  • 1,220
  • 1
  • 14
  • 24
0

Adding spring.data.mongodb.authentication-database=admin in your application.properties will set the authentication database to admin. This is equivalent to adding ?authSource=admin in your connection string.

0

This answer may not directly related to this question, but I hope it will help others. If you use uri then @ChanningQiu answer is fine. But if you use property for each param then you can try following way-

spring:
  data:
    mongodb:
      host: localhost
      port: 27017
      database: db_name
      username: db_user_name
      password: db_password
      authentication-database: admin

So in this case you need to set authentication-database: admin value.

Emdadul Sawon
  • 5,730
  • 3
  • 45
  • 48
0

Along with @Lutoslaw answer above: rollback to 4.2.2 works for me too.

I'v gotten the same error - Attempt to switch database target during SASL authentication - on createIndex operation.
It seems as my first operation under ordinary user after successful creation admin one.

It would be cool to know what has been so dramatically changed in the auth mechanism between those versions.