The current version of Mongo supports only very basic authentication. One authenticates a username and password in the context of a particular database. Once authenticated, the user has full read and write access to the database in question.
The admin database is special. In addition to several commands that are administrative being possible only on admin, authentication on admin gives one read and write access to all databases on the server. Effectively, admin access means root access to the db.
Note on a single socket we may authenticate for any number of databases, and as different users. This authentication persists for the life of the database connection (barring a logout command).
The Authentication Process
Authentication is a two step process. First the driver runs a getnonce command to get a nonce for use in the subsequent authentication. We can view a sample getnonce invocation from dbshell:
> db.$cmd.findOne({getnonce:1})
{ "nonce":"7268c504683936e1" , "ok":1
The nonce returned is a hex String.
The next step is to run an authenticate command for the database on which to authenticate. The authenticate command has the form:
{ authenticate : 1, user : username, nonce : nonce, key : digest }
where
- username is a username in the database's system.users collection;
- nonce is the nonce returned from a previous getnonce command;
- digest is the hex encoding of a MD5 message digest which is the MD5 hash of the concatenation of (nonce, username, password_digest), where password_digest is the user's password value in the pwd field of the associated user object in the database's system.users collection. pwd is the hex encoding of MD5( username + ":mongo:" + password_text).
Authenticate will return an object containing
when successful.
Details of why an authentication command failed may be found in the Mongo server's log files.
The following code from the Mongo Javascript driver provides an example implementation:
DB.prototype.addUser = function( username , pass ){
var c = this.getCollection( "system.users" );
var u = c.findOne( { user : username } ) || { user : username };
u.pwd = hex_md5( username + ":mongo:" + pass );
print( tojson( u ) );
c.save( u );
}
DB.prototype.auth = function( username , pass ){
var n = this.runCommand( { getnonce : 1 } );
var a = this.runCommand(
{
authenticate : 1 ,
user : username ,
nonce : n.nonce ,
key : hex_md5( n.nonce + username + hex_md5( username + ":mongo:" + pass ) )
}
);
return a.ok;
}
Logout
Drivers may optionally implement the logout command which deauthorizes usage for the specified database for this connection. Note other databases may still be authorized.
Alternatively, close the socket to deauthorize.
> db.$cmd.findOne({logout:1})
{
"ok" : 1.0
}
Replica Sets and Authentication
For drivers that support replica sets, extra care with replication is required.
When switching from one server in a replica set to another, for example in a failover situation, you must reauthenticate. Clients will likely want to cache authentication from the user so that the client can reauthenticate with the new server when appropriate.
Be careful also with operations such as Logout. If you log out from only some members of a replica set, that could be an issue.
Authenticating with a server in slave mode is allowed.
See Also
PLEASE POST QUESTIONS IN THE FORUMS: http://groups.google.com/group/mongodb-user. Post tips and clarifications here.
blog comments powered by Disqus