2
* Copyright (C) 2010 10gen Inc.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU Affero General Public License, version 3,
6
* as published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Affero General Public License for more details.
13
* You should have received a copy of the GNU Affero General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
#include "mongo/db/commands/authentication_commands.h"
19
#include <boost/scoped_ptr.hpp>
23
#include "mongo/base/status.h"
24
#include "mongo/client/sasl_client_authenticate.h"
25
#include "mongo/db/auth/action_set.h"
26
#include "mongo/db/auth/action_type.h"
27
#include "mongo/db/auth/authorization_manager.h"
28
#include "mongo/db/auth/mongo_authentication_session.h"
29
#include "mongo/db/auth/privilege.h"
30
#include "mongo/db/client_basic.h"
31
#include "mongo/db/commands.h"
32
#include "mongo/db/jsobj.h"
33
#include "mongo/platform/random.h"
34
#include "mongo/util/concurrency/mutex.h"
35
#include "mongo/util/md5.hpp"
39
static bool _areNonceAuthenticateCommandsEnabled = true;
40
static const char _nonceAuthenticateCommandsDisabledMessage[] =
41
"Challenge-response authentication using getnonce and authenticate commands is disabled.";
43
void CmdAuthenticate::disableCommand() { _areNonceAuthenticateCommandsEnabled = false; }
48
{ user : <username>, pwd : <pwd_digest>, ... }
50
getnonce sends nonce to client
52
client then sends { authenticate:1, nonce64:<nonce_str>, user:<username>, key:<key> }
54
where <key> is md5(<nonce_str><username><pwd_digest_str>) as a string
57
class CmdGetNonce : public Command {
61
_randMutex("getnonce"),
62
_random(SecureRandom::create()) {
65
virtual bool requiresAuth() { return false; }
66
virtual bool logTheOp() { return false; }
67
virtual bool slaveOk() const {
70
void help(stringstream& h) const { h << "internal"; }
71
virtual LockType locktype() const { return NONE; }
72
virtual void addRequiredPrivileges(const std::string& dbname,
73
const BSONObj& cmdObj,
74
std::vector<Privilege>* out) {} // No auth required
75
bool run(const string&, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
76
nonce64 n = getNextNonce();
79
result.append("nonce", ss.str() );
80
ClientBasic::getCurrent()->resetAuthenticationSession(
81
new MongoAuthenticationSession(n));
86
nonce64 getNextNonce() {
87
SimpleMutex::scoped_lock lk(_randMutex);
88
return _random->nextInt64();
91
SimpleMutex _randMutex; // Synchronizes accesses to _random.
92
boost::scoped_ptr<SecureRandom> _random;
95
bool CmdAuthenticate::run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
97
log() << " authenticate db: " << dbname << " " << cmdObj << endl;
99
string user = cmdObj.getStringField("user");
101
if (!_areNonceAuthenticateCommandsEnabled) {
102
// SERVER-8461, MONGODB-CR must be enabled for authenticating the internal user, so that
103
// cluster members may communicate with each other.
104
if (dbname != StringData("local", StringData::LiteralTag()) ||
105
user != internalSecurity.user) {
106
errmsg = _nonceAuthenticateCommandsDisabledMessage;
107
result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed);
112
string key = cmdObj.getStringField("key");
113
string received_nonce = cmdObj.getStringField("nonce");
115
if( user.empty() || key.empty() || received_nonce.empty() ) {
116
log() << "field missing/wrong type in received authenticate command "
119
errmsg = "auth fails";
121
result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed);
125
stringstream digestBuilder;
129
ClientBasic *client = ClientBasic::getCurrent();
130
AuthenticationSession *session = client->getAuthenticationSession();
131
if (!session || session->getType() != AuthenticationSession::SESSION_TYPE_MONGO) {
133
LOG(1) << "auth: No pending nonce" << endl;
136
nonce64 nonce = static_cast<MongoAuthenticationSession*>(session)->getNonce();
137
digestBuilder << hex << nonce;
138
reject = digestBuilder.str() != received_nonce;
140
LOG(1) << "auth: Authentication failed for " << dbname << '$' << user << endl;
143
client->resetAuthenticationSession(NULL);
146
log() << "auth: bad nonce received or getnonce not called. could be a driver bug or a security attack. db:" << dbname << endl;
147
errmsg = "auth fails";
149
result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed);
156
Status status = ClientBasic::getCurrent()->getAuthorizationManager()->getPrivilegeDocument(
157
dbname, PrincipalName(user, dbname), &userObj);
158
if (!status.isOK()) {
159
log() << status.reason() << std::endl;
160
errmsg = "auth fails";
161
result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed);
164
pwd = userObj["pwd"].String();
168
digestBuilder << user << pwd;
169
string done = digestBuilder.str();
173
md5_append(&st, (const md5_byte_t *) done.c_str(), done.size());
177
string computed = digestToString( d );
179
if ( key != computed ) {
180
log() << "auth: key mismatch " << user << ", ns:" << dbname << endl;
181
errmsg = "auth fails";
182
result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed);
186
AuthorizationManager* authorizationManager =
187
ClientBasic::getCurrent()->getAuthorizationManager();
188
Principal* principal = new Principal(PrincipalName(user, dbname));
189
principal->setImplicitPrivilegeAcquisition(true);
190
authorizationManager->addAuthorizedPrincipal(principal);
192
result.append( "dbname" , dbname );
193
result.append( "user" , user );
196
CmdAuthenticate cmdAuthenticate;
198
class CmdLogout : public Command {
200
virtual bool logTheOp() {
203
virtual bool slaveOk() const {
206
virtual void addRequiredPrivileges(const std::string& dbname,
207
const BSONObj& cmdObj,
208
std::vector<Privilege>* out) {} // No auth required
209
void help(stringstream& h) const { h << "de-authenticate"; }
210
virtual LockType locktype() const { return NONE; }
211
CmdLogout() : Command("logout") {}
212
bool run(const string& dbname,
216
BSONObjBuilder& result,
218
AuthorizationManager* authManager = ClientBasic::getCurrent()->getAuthorizationManager();
219
authManager->logoutDatabase(dbname);