Authentication is the process of verifying the identity of a user. In this article, we will see how to provide secured access to mongoDB database through authentication process.
If you haven’t installed MongoDb, read here for an introduction and the installation steps.
We will be using Maven as our build tool. In order to access MongoDB Java Driver API, include mongodb-driver
artifact.
Dependencies
Add mongodb-driver
artifact to your pom.xml.
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javarticles.spring.jms</groupId> <artifactId>springJms</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>3.2.0</version> </dependency> </dependencies> </project>
Steps in authenticating access to MongoDB
In order to authenticate a user, we must first add a user to the MongoDB.
- Connect to mongo shell
C:\mongodb\bin>mongo 2016-01-02T15:02:21.613+0530 I CONTROL [main]Hotfix KB2731284 or later update is not installed, will zero-out data files MongoDB shell version: 3.2.0 connecting to: test <
- Connect to the admin database
< use admin switched to db admin
- To create a user, you need to use
db.createUser()
method. You will assign roles to user based on the operations allowed on the resource where a resource can be either a database, collection, set of collections, or the cluster. The permissions are granted in the form of privileges. The first user created in the database should be a user administrator who has the privileges to manage other users. Let’s create a user administrator.< db.createUser( ... { ... user: "adminuser", ... pwd: "admin", ... roles: [ "root" ] ... } ... ) Successfully added user: { "user" : "adminuser", "roles" : [ "root" ] }
- Authorization is enabled by restarting the database server using the –auth.
- First shut down the server
< db.shutdownServer()
- Server is now down.
< db.shutdownServer() 2016-01-02T19:11:58.296+0530 I NETWORK [thread1] trying reconnect to 127.0.0.1: 27017 (127.0.0.1) failed 2016-01-02T19:11:58.300+0530 I NETWORK [thread1] reconnect 127.0.0.1:27017 (127 .0.0.1) ok server should be down...
- Now restart the database using the –-auth option, which forces user authentication:
C:\mongodb\bin>mongod.exe --dbpath "C:\mongodb\data" --auth
- Since the database server is started in secure mode, the client needs to authenticate. Let’s start mongo shell without and try to list the existing databases. You can see below, list databases failed.
C:\mongodb\bin>mongo 2016-01-02T19:17:44.350+0530 I CONTROL [main]Hotfix KB2731284 or later update is not installed, will zero-out data files MongoDB shell version: 3.2.0 connecting to: test > use mydb switched to db mydb > show dbs; 2016-01-02T19:18:51.637+0530 E QUERY [thread1] Error: listDatabases failed:{ "ok" : 0, "errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }", "code" : 13 } : [email protected]/mongo/shell/utils.js:23:13 [email protected]/mongo/shell/mongo.js:53:1 [email protected]/mongo/shell/utils.js:699:19 [email protected]/mongo/shell/utils.js:593:15 @(shellhelp2):1:1
- Let’s start mongo with authentication details. The client needs to authenticate against the ‘authentication database’.
authenticationDatabase
is the database where we have created the useradminuser
. In our case it was databaseadmin
.C:\mongodb\bin>mongo -u adminuser -p admin --authenticationDatabase admin 2016-01-02T19:29:55.069+0530 I CONTROL [main]Hotfix KB2731284 or later update is not installed, will zero-out data files MongoDB shell version: 3.2.0 connecting to: test
- Since mongo shell client has logged in with proper authentication details, listing of databases will work now as
myadmin
has all privileges.> show dbs; admin 0.000GB complexIdTest 0.000GB database 0.001GB issue 0.000GB local 0.000GB mongo-index-db1 0.000GB mongoRepositoryTextSearchIntegrationTests 0.000GB mydb 0.000GB repositories 0.000GB script-tests 0.000GB test 0.000GB validation 0.000GB
- Connect first to the mongod or mongos instance, and then run the authenticate command or the
db.auth()
method against the authentication database.C:\mongodb\bin>mongo 2016-01-02T20:14:00.487+0530 I CONTROL [main]Hotfix KB2731284 or later update is not installed, will zero-out data files MongoDB shell version: 3.2.0 connecting to: test > use admin switched to db admin > db.auth('adminuser', 'admin') 1 > show dbs; admin 0.000GB complexIdTest 0.000GB database 0.001GB issue 0.000GB local 0.000GB mongo-index-db1 0.000GB mongoRepositoryTextSearchIntegrationTests 0.000GB mydb 0.000GB repositories 0.000GB script-tests 0.000GB test 0.000GB validation 0.000GB >
MongoClient without authentication
If we start the client without authentication and try to execute some command on the database server, the command is going to fail with ‘not authorized….’ error.
MongoDBWithoutAuthenticationExample:
package com.javarticles.mongodb; import java.net.UnknownHostException; import com.mongodb.MongoClient; public class MongoDBWithoutAuthenticationExample { public static void main(String[] args) throws UnknownHostException { MongoClient mongoClient = new MongoClient(); try { for (String databaseName : mongoClient.listDatabaseNames()) { System.out.println("Database: " + databaseName); } } finally { mongoClient.close(); } } }
Output:
Jan 02, 2016 7:50:05 PM com.mongodb.diagnostics.logging.JULLogger log INFO: Cluster created with settings {hosts=[127.0.0.1:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500} Jan 02, 2016 7:50:05 PM com.mongodb.diagnostics.logging.JULLogger log INFO: No server chosen by ReadPreferenceServerSelector{readPreference=primary} from cluster description ClusterDescription{type=UNKNOWN, connectionMode=SINGLE, all=[ServerDescription{address=127.0.0.1:27017, type=UNKNOWN, state=CONNECTING}]}. Waiting for 30000 ms before timing out Jan 02, 2016 7:50:05 PM com.mongodb.diagnostics.logging.JULLogger log INFO: Opened connection [connectionId{localValue:1, serverValue:9}] to 127.0.0.1:27017 Jan 02, 2016 7:50:05 PM com.mongodb.diagnostics.logging.JULLogger log INFO: Monitor thread successfully connected to server with description ServerDescription{address=127.0.0.1:27017, type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 2, 0]}, minWireVersion=0, maxWireVersion=4, electionId=null, maxDocumentSize=16777216, roundTripTimeNanos=500974} Jan 02, 2016 7:50:05 PM com.mongodb.diagnostics.logging.JULLogger log INFO: Opened connection [connectionId{localValue:2, serverValue:10}] to 127.0.0.1:27017 Jan 02, 2016 7:50:05 PM com.mongodb.diagnostics.logging.JULLogger log INFO: Closed connection [connectionId{localValue:2, serverValue:10}] to 127.0.0.1:27017 because the pool has been closed. Exception in thread "main" com.mongodb.MongoCommandException: Command failed with error 13: 'not authorized on admin to execute command { listDatabases: 1 }' on server 127.0.0.1:27017. The full response is { "ok" : 0.0, "errmsg" : "not authorized on admin to execute command { listDatabases: 1 }", "code" : 13 } at com.mongodb.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:86) at com.mongodb.connection.CommandProtocol.execute(CommandProtocol.java:119) at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:159) at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:286) at com.mongodb.connection.DefaultServerConnection.command(DefaultServerConnection.java:173) at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:215) at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:206) at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:112) at com.mongodb.operation.ListDatabasesOperation$1.call(ListDatabasesOperation.java:104) at com.mongodb.operation.ListDatabasesOperation$1.call(ListDatabasesOperation.java:101) at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:239) at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:212) at com.mongodb.operation.ListDatabasesOperation.execute(ListDatabasesOperation.java:101) at com.mongodb.operation.ListDatabasesOperation.execute(ListDatabasesOperation.java:53) at com.mongodb.Mongo.execute(Mongo.java:773) at com.mongodb.Mongo$2.execute(Mongo.java:760) at com.mongodb.OperationIterable.iterator(OperationIterable.java:47) at com.mongodb.ListDatabasesIterableImpl.iterator(ListDatabasesIterableImpl.java:57) at com.mongodb.MappingIterable.iterator(MappingIterable.java:36) at com.mongodb.MappingIterable.iterator(MappingIterable.java:24) at com.javarticles.mongodb.MongoDBWithoutAuthenticationExample.main(MongoDBWithoutAuthenticationExample.java:12)
MongoClient authentication
Let’s instantiate MongoClient
with the authentication details and then try getting the database names.
We pass in security credentials, the user, authentication database and the password.
MongoCredential.createCredential("adminuser", "admin", "admin".toCharArray())
MongoDBWithAuthenticationExample:
package com.javarticles.mongodb; import java.net.UnknownHostException; import java.util.Arrays; import com.mongodb.MongoClient; import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; public class MongoDBWithAuthenticationExample { public static void main(String[] args) throws UnknownHostException { MongoClient mongoClient = new MongoClient(new ServerAddress(), Arrays.asList(MongoCredential.createCredential("adminuser", "admin", "admin".toCharArray()))); try { for (String databaseName : mongoClient.listDatabaseNames()) { System.out.println("Database: " + databaseName); } } finally { mongoClient.close(); } } }
Output:
Jan 02, 2016 8:06:10 PM com.mongodb.diagnostics.logging.JULLogger log INFO: Cluster created with settings {hosts=[127.0.0.1:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500} Jan 02, 2016 8:06:10 PM com.mongodb.diagnostics.logging.JULLogger log INFO: No server chosen by ReadPreferenceServerSelector{readPreference=primary} from cluster description ClusterDescription{type=UNKNOWN, connectionMode=SINGLE, all=[ServerDescription{address=127.0.0.1:27017, type=UNKNOWN, state=CONNECTING}]}. Waiting for 30000 ms before timing out Jan 02, 2016 8:06:11 PM com.mongodb.diagnostics.logging.JULLogger log INFO: Opened connection [connectionId{localValue:1, serverValue:129}] to 127.0.0.1:27017 Jan 02, 2016 8:06:11 PM com.mongodb.diagnostics.logging.JULLogger log INFO: Monitor thread successfully connected to server with description ServerDescription{address=127.0.0.1:27017, type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 2, 0]}, minWireVersion=0, maxWireVersion=4, electionId=null, maxDocumentSize=16777216, roundTripTimeNanos=935809} Jan 02, 2016 8:06:11 PM com.mongodb.diagnostics.logging.JULLogger log INFO: Opened connection [connectionId{localValue:2, serverValue:130}] to 127.0.0.1:27017 Database: admin Database: complexIdTest Database: database Database: issue Database: local Database: mongo-index-db1 Database: mongoRepositoryTextSearchIntegrationTests Database: mydb Database: repositories Database: script-tests Database: test Database: validation Jan 02, 2016 8:06:11 PM com.mongodb.diagnostics.logging.JULLogger log INFO: Closed connection [connectionId{localValue:2, serverValue:130}] to 127.0.0.1:27017 because the pool has been closed.
Download the source code
This was an example about accessing MongoDB in a secured way.