2009-01-19 01:13:12 +01:00
// security_commands.cpp
// security.cpp links with both dbgrid and db. this file db only -- at least for now.
// security.cpp
# include "stdafx.h"
# include "security.h"
# include "../util/md5.hpp"
# include "json.h"
# include "pdfile.h"
# include "db.h"
# include "dbhelpers.h"
# include "commands.h"
# include "jsobj.h"
namespace mongo {
/* authentication
system . users contains
2009-01-21 21:06:13 +01:00
{ user : < username > , pwd : < pwd_digest > , . . . }
2009-01-19 01:13:12 +01:00
getnonce sends nonce to client
2009-01-21 21:06:13 +01:00
client then sends { authenticate : 1 , nonce : < nonce_str > , user : < username > , key : < key > }
2009-01-19 01:13:12 +01:00
2009-01-21 21:06:13 +01:00
where < key > is md5 ( < nonce_str > < username > < pwd_digest_str > ) as a string
2009-01-19 01:13:12 +01:00
*/
2009-01-21 21:06:13 +01:00
boost : : thread_specific_ptr < nonce > lastNonce ;
2009-01-19 01:13:12 +01:00
class CmdGetNonce : public Command {
public :
2009-01-19 02:31:33 +01:00
virtual bool requiresAuth ( ) { return false ; }
2009-01-19 01:13:12 +01:00
virtual bool logTheOp ( ) {
return false ;
}
virtual bool slaveOk ( ) {
return true ;
}
CmdGetNonce ( ) : Command ( " getnonce " ) { }
bool run ( const char * ns , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2009-01-21 21:06:13 +01:00
nonce * n = new nonce ( security . getNonce ( ) ) ;
2009-01-20 17:37:15 +01:00
stringstream ss ;
2009-01-21 21:06:13 +01:00
ss < < hex < < * n ;
2009-01-20 17:37:15 +01:00
result . append ( " nonce " , ss . str ( ) ) ;
2009-01-21 21:06:13 +01:00
lastNonce . reset ( n ) ;
2009-01-19 01:13:12 +01:00
return true ;
}
} cmdGetNonce ;
class CmdLogout : public Command {
public :
virtual bool logTheOp ( ) {
return false ;
}
virtual bool slaveOk ( ) {
return true ;
}
CmdLogout ( ) : Command ( " logout " ) { }
bool run ( const char * ns , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
// database->name is the one we are logging out...
2009-01-19 02:31:33 +01:00
AuthenticationInfo * ai = authInfo . get ( ) ;
assert ( ai ) ;
ai - > logout ( database - > name . c_str ( ) ) ;
2009-01-19 01:13:12 +01:00
return true ;
}
} cmdLogout ;
2009-01-20 20:30:59 +01:00
2009-01-19 01:13:12 +01:00
class CmdAuthenticate : public Command {
public :
2009-01-19 02:31:33 +01:00
virtual bool requiresAuth ( ) { return false ; }
2009-01-19 01:13:12 +01:00
virtual bool logTheOp ( ) {
return false ;
}
virtual bool slaveOk ( ) {
return true ;
}
CmdAuthenticate ( ) : Command ( " authenticate " ) { }
bool run ( const char * ns , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2009-01-20 20:30:59 +01:00
log ( 1 ) < < " authenticate: " < < cmdObj < < endl ;
2009-01-19 01:13:12 +01:00
string user = cmdObj . getStringField ( " user " ) ;
2009-01-20 17:37:15 +01:00
string key = cmdObj . getStringField ( " key " ) ;
2009-01-21 21:06:13 +01:00
string received_nonce = cmdObj . getStringField ( " nonce " ) ;
2009-01-20 17:37:15 +01:00
2009-01-21 21:06:13 +01:00
if ( user . empty ( ) | | key . empty ( ) | | received_nonce . empty ( ) ) {
2009-01-19 01:13:12 +01:00
log ( ) < < " field missing/wrong type in received authenticate command " < < database - > name < < ' \n ' ; log ( ) < < " field missing/wrong type in received authenticate command " < < database - > name < < ' \n ' ;
errmsg = " auth fails " ;
sleepmillis ( 10 ) ;
return false ;
}
2009-01-20 17:37:15 +01:00
stringstream digestBuilder ;
2009-01-19 01:13:12 +01:00
{
2009-01-21 21:06:13 +01:00
nonce * ln = lastNonce . release ( ) ;
digestBuilder < < hex < < * ln ;
2009-01-20 17:37:15 +01:00
2009-01-21 21:06:13 +01:00
if ( ln = = 0 | | digestBuilder . str ( ) ! = received_nonce ) {
2009-01-19 01:13:12 +01:00
log ( ) < < " auth: bad nonce received. could be a driver bug or a security attack. db: " < < database - > name < < ' \n ' ; log ( ) < < " field missing/wr " < < database - > name < < ' \n ' ;
errmsg = " auth fails " ;
sleepmillis ( 30 ) ;
return false ;
}
}
static BSONObj userPattern = fromjson ( " { \" user \" :1} " ) ;
string systemUsers = database - > name + " .system.users " ;
OCCASIONALLY Helpers : : ensureIndex ( systemUsers . c_str ( ) , userPattern , " user_1 " ) ;
BSONObj userObj ;
{
BSONObjBuilder b ;
b < < " user " < < user ;
BSONObj query = b . done ( ) ;
if ( ! Helpers : : findOne ( systemUsers . c_str ( ) , query , userObj ) ) {
log ( ) < < " auth: couldn't find user " < < user < < " , " < < systemUsers < < ' \n ' ;
errmsg = " auth fails " ;
return false ;
}
}
2009-01-20 17:37:15 +01:00
2009-01-19 01:13:12 +01:00
md5digest d ;
{
2009-01-20 17:37:15 +01:00
string pwd = userObj . getStringField ( " pwd " ) ;
digestBuilder < < user < < pwd ;
string done = digestBuilder . str ( ) ;
2009-01-19 01:13:12 +01:00
md5_state_t st ;
md5_init ( & st ) ;
2009-01-20 17:37:15 +01:00
md5_append ( & st , ( const md5_byte_t * ) done . c_str ( ) , done . size ( ) ) ;
2009-01-19 01:13:12 +01:00
md5_finish ( & st , d ) ;
}
2009-01-20 17:37:15 +01:00
string computed = digestToString ( d ) ;
if ( key ! = computed ) {
2009-01-19 01:13:12 +01:00
log ( ) < < " auth: key mismatch " < < user < < " , ns: " < < ns < < ' \n ' ;
errmsg = " auth fails " ;
return false ;
}
2009-01-19 02:31:33 +01:00
AuthenticationInfo * ai = authInfo . get ( ) ;
assert ( ai ) ;
ai - > authorize ( database - > name . c_str ( ) ) ;
2009-01-19 01:13:12 +01:00
return true ;
}
} cmdAuthenticate ;
2009-01-20 17:37:15 +01:00
2009-01-19 01:13:12 +01:00
} // namespace mongo