1
// security_commands.cpp
2
// security.cpp links with both dbgrid and db. this file db only -- at least for now.
8
#include "../util/md5.hpp"
12
#include "dbhelpers.h"
22
{ user : <username>, pwd : <pwd_digest>, ... }
24
getnonce sends nonce to client
26
client then sends { authenticate:1, nonce:<nonce_str>, user:<username>, key:<key> }
28
where <key> is md5(<nonce_str><username><pwd_digest_str>) as a string
31
boost::thread_specific_ptr<nonce> lastNonce;
33
class CmdGetNonce : public Command {
35
virtual bool requiresAuth() { return false; }
36
virtual bool logTheOp() {
39
virtual bool slaveOk() {
42
CmdGetNonce() : Command("getnonce") {}
43
bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
44
nonce *n = new nonce(security.getNonce());
47
result.append("nonce", ss.str() );
53
class CmdLogout : public Command {
55
virtual bool logTheOp() {
58
virtual bool slaveOk() {
61
CmdLogout() : Command("logout") {}
62
bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
63
// database->name is the one we are logging out...
64
Client& client = cc();
65
AuthenticationInfo *ai = client.ai;
66
ai->logout(client.database()->name.c_str());
71
class CmdAuthenticate : public Command {
73
virtual bool requiresAuth() { return false; }
74
virtual bool logTheOp() {
77
virtual bool slaveOk() {
80
CmdAuthenticate() : Command("authenticate") {}
81
bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
82
log(1) << " authenticate: " << cmdObj << endl;
84
string user = cmdObj.getStringField("user");
85
string key = cmdObj.getStringField("key");
86
string received_nonce = cmdObj.getStringField("nonce");
88
if( user.empty() || key.empty() || received_nonce.empty() ) {
89
log() << "field missing/wrong type in received authenticate command "
90
<< cc().database()->name
92
errmsg = "auth fails";
97
stringstream digestBuilder;
101
nonce *ln = lastNonce.release();
105
digestBuilder << hex << *ln;
106
reject = digestBuilder.str() != received_nonce;
110
log() << "auth: bad nonce received or getnonce not called. could be a driver bug or a security attack. db:" << cc().database()->name << '\n';
111
errmsg = "auth fails";
117
static BSONObj userPattern = fromjson("{\"user\":1}");
118
string systemUsers = cc().database()->name + ".system.users";
119
OCCASIONALLY Helpers::ensureIndex(systemUsers.c_str(), userPattern, false, "user_1");
125
BSONObj query = b.done();
126
if( !Helpers::findOne(systemUsers.c_str(), query, userObj) ) {
127
log() << "auth: couldn't find user " << user << ", " << systemUsers << '\n';
128
errmsg = "auth fails";
136
string pwd = userObj.getStringField("pwd");
137
digestBuilder << user << pwd;
138
string done = digestBuilder.str();
142
md5_append(&st, (const md5_byte_t *) done.c_str(), done.size());
146
string computed = digestToString( d );
148
if ( key != computed ){
149
log() << "auth: key mismatch " << user << ", ns:" << ns << '\n';
150
errmsg = "auth fails";
154
AuthenticationInfo *ai = currentClient.get()->ai;
155
ai->authorize(cc().database()->name.c_str());