~evarlast/ubuntu/trusty/mongodb/upstart-workaround-debian-bug-718702

« back to all changes in this revision

Viewing changes to src/mongo/db/commands/authentication_commands.cpp

  • Committer: Package Import Robot
  • Author(s): James Page, James Page, Robie Basak
  • Date: 2013-05-29 17:44:42 UTC
  • mfrom: (44.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20130529174442-z0a4qmoww4y0t458
Tags: 1:2.4.3-1ubuntu1
[ James Page ]
* Merge from Debian unstable, remaining changes:
  - Enable SSL support:
    + d/control: Add libssl-dev to BD's.
    + d/rules: Enabled --ssl option.
    + d/mongodb.conf: Add example SSL configuration options.
  - d/mongodb-server.mongodb.upstart: Add upstart configuration.
  - d/rules: Don't strip binaries during scons build for Ubuntu.
  - d/control: Add armhf to target archs.
  - d/p/SConscript.client.patch: fixup install of client libraries.
  - d/p/0010-install-libs-to-usr-lib-not-usr-lib64-Closes-588557.patch:
    Install libraries to lib not lib64.
* Dropped changes:
  - d/p/arm-support.patch: Included in Debian.
  - d/p/double-alignment.patch: Included in Debian.
  - d/rules,control: Debian also builds with avaliable system libraries
    now.
* Fix FTBFS due to gcc and boost upgrades in saucy:
  - d/p/0008-ignore-unused-local-typedefs.patch: Add -Wno-unused-typedefs
    to unbreak building with g++-4.8.
  - d/p/0009-boost-1.53.patch: Fixup signed/unsigned casting issue.

[ Robie Basak ]
* d/p/0011-Use-a-signed-char-to-store-BSONType-enumerations.patch: Fixup
  build failure on ARM due to missing signed'ness of char cast.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
*    Copyright (C) 2010 10gen Inc.
 
3
*
 
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.
 
7
*
 
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.
 
12
*
 
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/>.
 
15
*/
 
16
 
 
17
#include "mongo/db/commands/authentication_commands.h"
 
18
 
 
19
#include <boost/scoped_ptr.hpp>
 
20
#include <string>
 
21
#include <vector>
 
22
 
 
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"
 
36
 
 
37
namespace mongo {
 
38
 
 
39
    static bool _areNonceAuthenticateCommandsEnabled = true;
 
40
    static const char _nonceAuthenticateCommandsDisabledMessage[] =
 
41
        "Challenge-response authentication using getnonce and authenticate commands is disabled.";
 
42
 
 
43
    void CmdAuthenticate::disableCommand() { _areNonceAuthenticateCommandsEnabled = false; }
 
44
 
 
45
    /* authentication
 
46
 
 
47
       system.users contains
 
48
         { user : <username>, pwd : <pwd_digest>, ... }
 
49
 
 
50
       getnonce sends nonce to client
 
51
 
 
52
       client then sends { authenticate:1, nonce64:<nonce_str>, user:<username>, key:<key> }
 
53
 
 
54
       where <key> is md5(<nonce_str><username><pwd_digest_str>) as a string
 
55
    */
 
56
 
 
57
    class CmdGetNonce : public Command {
 
58
    public:
 
59
        CmdGetNonce() :
 
60
            Command("getnonce"),
 
61
            _randMutex("getnonce"),
 
62
            _random(SecureRandom::create()) {
 
63
        }
 
64
 
 
65
        virtual bool requiresAuth() { return false; }
 
66
        virtual bool logTheOp() { return false; }
 
67
        virtual bool slaveOk() const {
 
68
            return true;
 
69
        }
 
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();
 
77
            stringstream ss;
 
78
            ss << hex << n;
 
79
            result.append("nonce", ss.str() );
 
80
            ClientBasic::getCurrent()->resetAuthenticationSession(
 
81
                    new MongoAuthenticationSession(n));
 
82
            return true;
 
83
        }
 
84
 
 
85
    private:
 
86
        nonce64 getNextNonce() {
 
87
            SimpleMutex::scoped_lock lk(_randMutex);
 
88
            return _random->nextInt64();
 
89
        }
 
90
 
 
91
        SimpleMutex _randMutex;  // Synchronizes accesses to _random.
 
92
        boost::scoped_ptr<SecureRandom> _random;
 
93
    } cmdGetNonce;
 
94
 
 
95
    bool CmdAuthenticate::run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
 
96
 
 
97
        log() << " authenticate db: " << dbname << " " << cmdObj << endl;
 
98
 
 
99
        string user = cmdObj.getStringField("user");
 
100
 
 
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);
 
108
                return false;
 
109
            }
 
110
        }
 
111
 
 
112
        string key = cmdObj.getStringField("key");
 
113
        string received_nonce = cmdObj.getStringField("nonce");
 
114
 
 
115
        if( user.empty() || key.empty() || received_nonce.empty() ) {
 
116
            log() << "field missing/wrong type in received authenticate command "
 
117
                  << dbname
 
118
                  << endl;
 
119
            errmsg = "auth fails";
 
120
            sleepmillis(10);
 
121
            result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed);
 
122
            return false;
 
123
        }
 
124
 
 
125
        stringstream digestBuilder;
 
126
 
 
127
        {
 
128
            bool reject = false;
 
129
            ClientBasic *client = ClientBasic::getCurrent();
 
130
            AuthenticationSession *session = client->getAuthenticationSession();
 
131
            if (!session || session->getType() != AuthenticationSession::SESSION_TYPE_MONGO) {
 
132
                reject = true;
 
133
                LOG(1) << "auth: No pending nonce" << endl;
 
134
            }
 
135
            else {
 
136
                nonce64 nonce = static_cast<MongoAuthenticationSession*>(session)->getNonce();
 
137
                digestBuilder << hex << nonce;
 
138
                reject = digestBuilder.str() != received_nonce;
 
139
                if ( reject ) {
 
140
                    LOG(1) << "auth: Authentication failed for " << dbname << '$' << user << endl;
 
141
                }
 
142
            }
 
143
            client->resetAuthenticationSession(NULL);
 
144
 
 
145
            if ( reject ) {
 
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";
 
148
                sleepmillis(30);
 
149
                result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed);
 
150
                return false;
 
151
            }
 
152
        }
 
153
 
 
154
        BSONObj userObj;
 
155
        string pwd;
 
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);
 
162
            return false;
 
163
        }
 
164
        pwd = userObj["pwd"].String();
 
165
 
 
166
        md5digest d;
 
167
        {
 
168
            digestBuilder << user << pwd;
 
169
            string done = digestBuilder.str();
 
170
 
 
171
            md5_state_t st;
 
172
            md5_init(&st);
 
173
            md5_append(&st, (const md5_byte_t *) done.c_str(), done.size());
 
174
            md5_finish(&st, d);
 
175
        }
 
176
 
 
177
        string computed = digestToString( d );
 
178
 
 
179
        if ( key != computed ) {
 
180
            log() << "auth: key mismatch " << user << ", ns:" << dbname << endl;
 
181
            errmsg = "auth fails";
 
182
            result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed);
 
183
            return false;
 
184
        }
 
185
 
 
186
        AuthorizationManager* authorizationManager =
 
187
            ClientBasic::getCurrent()->getAuthorizationManager();
 
188
        Principal* principal = new Principal(PrincipalName(user, dbname));
 
189
        principal->setImplicitPrivilegeAcquisition(true);
 
190
        authorizationManager->addAuthorizedPrincipal(principal);
 
191
 
 
192
        result.append( "dbname" , dbname );
 
193
        result.append( "user" , user );
 
194
        return true;
 
195
    }
 
196
    CmdAuthenticate cmdAuthenticate;
 
197
 
 
198
    class CmdLogout : public Command {
 
199
    public:
 
200
        virtual bool logTheOp() {
 
201
            return false;
 
202
        }
 
203
        virtual bool slaveOk() const {
 
204
            return true;
 
205
        }
 
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,
 
213
                 BSONObj& cmdObj,
 
214
                 int options,
 
215
                 string& errmsg,
 
216
                 BSONObjBuilder& result,
 
217
                 bool fromRepl) {
 
218
            AuthorizationManager* authManager = ClientBasic::getCurrent()->getAuthorizationManager();
 
219
            authManager->logoutDatabase(dbname);
 
220
            return true;
 
221
        }
 
222
    } cmdLogout;
 
223
}