~ubuntu-branches/ubuntu/trusty/mongodb/trusty-proposed

« back to all changes in this revision

Viewing changes to db/security_commands.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Antonin Kral
  • Date: 2010-01-29 19:48:45 UTC
  • Revision ID: james.westby@ubuntu.com-20100129194845-8wbmkf626fwcavc9
Tags: upstream-1.3.1
ImportĀ upstreamĀ versionĀ 1.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// security_commands.cpp
 
2
// security.cpp links with both dbgrid and db.  this file db only -- at least for now.
 
3
 
 
4
// security.cpp
 
5
 
 
6
#include "stdafx.h"
 
7
#include "security.h"
 
8
#include "../util/md5.hpp"
 
9
#include "json.h" 
 
10
#include "pdfile.h"
 
11
#include "db.h"
 
12
#include "dbhelpers.h"
 
13
#include "commands.h"
 
14
#include "jsobj.h"
 
15
#include "client.h"
 
16
 
 
17
namespace mongo {
 
18
 
 
19
/* authentication
 
20
 
 
21
   system.users contains 
 
22
     { user : <username>, pwd : <pwd_digest>, ... }
 
23
 
 
24
   getnonce sends nonce to client
 
25
 
 
26
   client then sends { authenticate:1, nonce:<nonce_str>, user:<username>, key:<key> }
 
27
 
 
28
   where <key> is md5(<nonce_str><username><pwd_digest_str>) as a string
 
29
*/
 
30
 
 
31
    boost::thread_specific_ptr<nonce> lastNonce;
 
32
 
 
33
    class CmdGetNonce : public Command {
 
34
    public:
 
35
        virtual bool requiresAuth() { return false; }
 
36
        virtual bool logTheOp() {
 
37
            return false;
 
38
        }
 
39
        virtual bool slaveOk() {
 
40
            return true;
 
41
        }
 
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());
 
45
            stringstream ss;
 
46
            ss << hex << *n;
 
47
            result.append("nonce", ss.str() );
 
48
            lastNonce.reset(n);
 
49
            return true;
 
50
        }
 
51
    } cmdGetNonce;
 
52
 
 
53
    class CmdLogout : public Command {
 
54
    public:
 
55
        virtual bool logTheOp() {
 
56
            return false;
 
57
        }
 
58
        virtual bool slaveOk() {
 
59
            return true;
 
60
        }
 
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());
 
67
            return true;
 
68
        }
 
69
    } cmdLogout;
 
70
    
 
71
    class CmdAuthenticate : public Command {
 
72
    public:
 
73
        virtual bool requiresAuth() { return false; }
 
74
        virtual bool logTheOp() {
 
75
            return false;
 
76
        }
 
77
        virtual bool slaveOk() {
 
78
            return true;
 
79
        }
 
80
        CmdAuthenticate() : Command("authenticate") {}
 
81
        bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
 
82
            log(1) << " authenticate: " << cmdObj << endl;
 
83
 
 
84
            string user = cmdObj.getStringField("user");
 
85
            string key = cmdObj.getStringField("key");
 
86
            string received_nonce = cmdObj.getStringField("nonce");
 
87
            
 
88
            if( user.empty() || key.empty() || received_nonce.empty() ) { 
 
89
                log() << "field missing/wrong type in received authenticate command " 
 
90
                    << cc().database()->name
 
91
                    << '\n';               
 
92
                errmsg = "auth fails";
 
93
                sleepmillis(10);
 
94
                return false;
 
95
            }
 
96
            
 
97
            stringstream digestBuilder;
 
98
 
 
99
            {
 
100
                bool reject = false;
 
101
                nonce *ln = lastNonce.release();
 
102
                if ( ln == 0 ) {
 
103
                    reject = true;
 
104
                } else {
 
105
                    digestBuilder << hex << *ln;
 
106
                    reject = digestBuilder.str() != received_nonce;
 
107
                }
 
108
                    
 
109
                if ( reject ) {
 
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";
 
112
                    sleepmillis(30);
 
113
                    return false;
 
114
                }
 
115
            }
 
116
 
 
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");
 
120
 
 
121
            BSONObj userObj;
 
122
            {
 
123
                BSONObjBuilder b;
 
124
                b << "user" << user;
 
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";
 
129
                    return false;
 
130
                }
 
131
            }
 
132
            
 
133
            md5digest d;
 
134
            {
 
135
                
 
136
                string pwd = userObj.getStringField("pwd");
 
137
                digestBuilder << user << pwd;
 
138
                string done = digestBuilder.str();
 
139
                
 
140
                md5_state_t st;
 
141
                md5_init(&st);
 
142
                md5_append(&st, (const md5_byte_t *) done.c_str(), done.size());
 
143
                md5_finish(&st, d);
 
144
            }
 
145
            
 
146
            string computed = digestToString( d );
 
147
            
 
148
            if ( key != computed ){
 
149
                log() << "auth: key mismatch " << user << ", ns:" << ns << '\n';
 
150
                errmsg = "auth fails";
 
151
                return false;
 
152
            }
 
153
 
 
154
            AuthenticationInfo *ai = currentClient.get()->ai;
 
155
            ai->authorize(cc().database()->name.c_str());
 
156
            return true;
 
157
        }
 
158
    } cmdAuthenticate;
 
159
    
 
160
} // namespace mongo