I am currently trying to connect to a MongoDB replica set using the (relatively) new 3.0 Java driver. However I can't seem to catch the MongoSecurityExceptions that occur when the user provides bad credentials. This is my current code.
try {
MongoClientURI mongoClientURI = new MongoClientURI("mongodb://<user>:<password>@member1.com:27017/?authSource=db"
this.mongoClient = new MongoClient(mongoClientURI);
}
catch(Exception e) {
// TODO: some proper exception handling
System.err.println(e.toLocalizedMessage());
}
This code works fine when run with correct credentials, but an exception is thrown outside of the try-catch when bad credentials are provided.
com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=null, userName='<user>', source='<source>', password=<hidden>, mechanismProperties={}}
at com.mongodb.connection.SaslAuthenticator.authenticate(SaslAuthenticator.java:61)
at com.mongodb.connection.DefaultAuthenticator.authenticate(DefaultAuthenticator.java:32)
at com.mongodb.connection.InternalStreamConnectionInitializer.authenticateAll(InternalStreamConnectionInitializer.java:99)
at com.mongodb.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:44)
at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:115)
at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:127)
at java.lang.Thread.run(Thread.java:745)
Any idea where to handle authentication exceptions?
The MongoClient constructors do not throw any connectivity-related exceptions. Rather, they return immediately after starting one or more background threads that attempt to establish a connection and authenticate based on the provided credentials.
It's only when an application uses the MongoClient to perform some operation on the MongoDB server that an exception will be thrown. However, that exception is a generic timeout exception indicating that the driver failed to find a suitable server for the operation before the server selection timeout expires. For example:
MongoClient client = new MongoClient(asList(new ServerAddress("localhost"), new ServerAddress("localhost:27018")),
singletonList(MongoCredential.createCredential("username",
"admin",
"bad".toCharArray())),
MongoClientOptions.builder().serverSelectionTimeout(1000).build());
try {
client.getDB("admin").command("ping");
} catch (MongoTimeoutException e) {
// do something
}
will throw a MongoTimeoutException after 1 second. While no MongoSecurityException is thrown, the message of the MongoTimeoutException will contain relevant details. For example, when connecting to a three member replica set when one of the servers is down, and authentication failed on the remaining two, the message field of the MongoTimeoutException will be something like:
Timed out after 1000 ms while waiting for a server that matches
ReadPreferenceServerSelector{readPreference=primary}. Client view of
cluster state is {type=UNKNOWN, servers=[{address=localhost:27017,
type=UNKNOWN, state=CONNECTING,
exception={com.mongodb.MongoSocketOpenException: Exception opening
socket}, caused by {java.net.ConnectException: Connection refused}},
{address=localhost:27018, type=UNKNOWN, state=CONNECTING,
exception={com.mongodb.MongoSecurityException: Exception
authenticating MongoCredential{mechanism=null, userName='username',
source='admin', password=, mechanismProperties={}}}, caused by
{com.mongodb.MongoCommandException: Command failed with error 18:
'Authentication failed.' on server localhost:27018. The full response
is { "ok" : 0.0, "code" : 18, "errmsg" : "Authentication failed." }}}]