void receivedGetMore(DbResponse& dbresponse, /*AbstractMessagingPort& dbMsgPort, */Message& m, stringstream& ss) { DbMessage d(m); const char *ns = d.getns(); ss << ns; setClient(ns); cc().top.setRead(); int ntoreturn = d.pullInt(); long long cursorid = d.pullInt64(); ss << " cid:" << cursorid; ss << " ntoreturn:" << ntoreturn; QueryResult* msgdata; try { AuthenticationInfo *ai = currentClient.get()->ai; uassert("unauthorized", ai->isAuthorized(cc().database()->name.c_str())); msgdata = getMore(ns, ntoreturn, cursorid, ss); } catch ( AssertionException& e ) { ss << " exception " + e.toString(); msgdata = emptyMoreResult(cursorid); } Message *resp = new Message(); resp->setData(msgdata, true); ss << " bytes:" << resp->data->dataLen(); ss << " nreturned:" << msgdata->nReturned; dbresponse.response = resp; dbresponse.responseTo = m.data->id; //dbMsgPort.reply(m, resp); }
bool CmdLogout::run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthenticationInfo *ai = ClientInfo::get()->getAuthenticationInfo(); AuthorizationManager* authManager = ClientInfo::get()->getAuthorizationManager(); ai->logout(dbname); authManager->logoutDatabase(dbname); return true; }
bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { // database->name is the one we are logging out... AuthenticationInfo *ai = authInfo.get(); assert( ai ); ai->logout(database->name.c_str()); return true; }
void CmdAuthenticate::authenticate(const string& dbname, const string& user, const bool readOnly) { AuthenticationInfo *ai = ClientInfo::get()->getAuthenticationInfo(); if ( readOnly ) { ai->authorizeReadOnly( dbname , user ); } else { ai->authorize( dbname , user ); } }
void CmdAuthenticate::authenticate(const string& dbname, const string& user, const bool readOnly) { ClientBasic* c = ClientBasic::getCurrent(); assert(c); AuthenticationInfo *ai = c->getAuthenticationInfo(); if ( readOnly ) { ai->authorizeReadOnly( dbname , user ); } else { ai->authorize( dbname , user ); } }
void killOp( Message &m, DbResponse &dbresponse ) { BSONObj obj; AuthenticationInfo *ai = currentClient.get()->ai; if( !ai->isAuthorized("admin") ) { obj = fromjson("{\"err\":\"unauthorized\"}"); } else if( !dbMutexInfo.isLocked() ) obj = fromjson("{\"info\":\"no op in progress/not locked\"}"); else { killCurrentOp = 1; obj = fromjson("{\"info\":\"attempting to kill op\"}"); } replyToQuery(0, m, dbresponse, obj); }
bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthenticationInfo *ai = cc().getAuthenticationInfo(); uassert( 12598 , "$eval reads unauthorized", ai->isAuthorizedReads(dbname.c_str()) ); if ( cmdObj["nolock"].trueValue() ) { return dbEval(dbname, cmdObj, result, errmsg); } // write security will be enforced in DBDirectClient mongolock lk( ai->isAuthorized( dbname.c_str() ) ); Client::Context ctx( dbname ); return dbEval(dbname, cmdObj, result, errmsg); }
bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthenticationInfo *ai = cc().getAuthenticationInfo(); uassert( 12598 , "$eval reads unauthorized", ai->isAuthorizedReads(dbname.c_str()) ); if ( cmdObj["nolock"].trueValue() ) { return dbEval(dbname, cmdObj, result, errmsg); } // write security will be enforced in DBDirectClient // TODO: should this be a db lock? scoped_ptr<Lock::ScopedLock> lk( ai->isAuthorized( dbname.c_str() ) ? static_cast<Lock::ScopedLock*>( new Lock::GlobalWrite() ) : static_cast<Lock::ScopedLock*>( new Lock::GlobalRead() ) ); Client::Context ctx( dbname ); return dbEval(dbname, cmdObj, result, errmsg); }
void inProgCmd( Message &m, DbResponse &dbresponse ) { BSONObjBuilder b; AuthenticationInfo *ai = cc().ai; if( !ai->isAuthorized("admin") ) { BSONObjBuilder b; b.append("err", "unauthorized"); } else { vector<BSONObj> vals; { boostlock bl(Client::clientsMutex); for( set<Client*>::iterator i = Client::clients.begin(); i != Client::clients.end(); i++ ) { Client *c = *i; CurOp& co = *(c->curop()); if( co.active ) vals.push_back( co.infoNoauth() ); } } b.append("inprog", vals); } replyToQuery(0, m, dbresponse, b.obj()); }
// Returns false when request includes 'end' bool assembleResponse( Message &m, DbResponse &dbresponse, const sockaddr_in &client ) { // before we lock... if ( m.data->operation() == dbQuery ) { const char *ns = m.data->_data + 4; if( strstr(ns, "$cmd.sys.") ) { if( strstr(ns, "$cmd.sys.inprog") ) { inProgCmd(m, dbresponse); return true; } if( strstr(ns, "$cmd.sys.killop") ) { killOp(m, dbresponse); return true; } } } if ( handlePossibleShardedMessage( m , dbresponse ) ){ /* important to do this before we lock so if a message has to be forwarded, doesn't block for that */ return true; } dblock lk; stringstream ss; char buf[64]; time_t now = time(0); CurOp& currentOp = *cc().curop(); currentOp.reset(now, client); time_t_to_String(now, buf); buf[20] = 0; // don't want the year ss << buf; Timer t; Client& c = cc(); c.clearns(); int logThreshold = 100; int ms; bool log = logLevel >= 1; c.curop()->op = m.data->operation(); #if 0 /* use this if you only want to process operations for a particular namespace. maybe add to cmd line parms or something fancier. */ DbMessage ddd(m); if ( strncmp(ddd.getns(), "clusterstock", 12) != 0 ) { static int q; if ( ++q < 20 ) out() << "TEMP skip " << ddd.getns() << endl; goto skip; } #endif if ( m.data->operation() == dbQuery ) { // receivedQuery() does its own authorization processing. receivedQuery(dbresponse, m, ss, true); } else if ( m.data->operation() == dbGetMore ) { // receivedQuery() does its own authorization processing. OPREAD; DEV log = true; ss << "getmore "; receivedGetMore(dbresponse, m, ss); } else if ( m.data->operation() == dbMsg ) { /* deprecated / rarely used. intended for connection diagnostics. */ ss << "msg "; char *p = m.data->_data; int len = strlen(p); if ( len > 400 ) out() << curTimeMillis() % 10000 << " long msg received, len:" << len << " ends with: " << p + len - 10 << endl; bool end = false; //strcmp("end", p) == 0; Message *resp = new Message(); resp->setData(opReply, "i am fine"); dbresponse.response = resp; dbresponse.responseTo = m.data->id; //dbMsgPort.reply(m, resp); if ( end ) return false; } else { const char *ns = m.data->_data + 4; char cl[256]; nsToClient(ns, cl); strncpy(currentOp.ns, ns, Namespace::MaxNsLen); AuthenticationInfo *ai = currentClient.get()->ai; if( !ai->isAuthorized(cl) ) { uassert_nothrow("unauthorized"); } else if ( m.data->operation() == dbInsert ) { OPWRITE; try { ss << "insert "; receivedInsert(m, ss); } catch ( AssertionException& e ) { LOGSOME problem() << " Caught Assertion insert, continuing\n"; ss << " exception " + e.toString(); } } else if ( m.data->operation() == dbUpdate ) { OPWRITE; try { ss << "update "; receivedUpdate(m, ss); } catch ( AssertionException& e ) { LOGSOME problem() << " Caught Assertion update, continuing" << endl; ss << " exception " + e.toString(); } } else if ( m.data->operation() == dbDelete ) { OPWRITE; try { ss << "remove "; receivedDelete(m, ss); } catch ( AssertionException& e ) { LOGSOME problem() << " Caught Assertion receivedDelete, continuing" << endl; ss << " exception " + e.toString(); } } else if ( m.data->operation() == dbKillCursors ) { OPREAD; try { logThreshold = 10; ss << "killcursors "; receivedKillCursors(m); } catch ( AssertionException& e ) { problem() << " Caught Assertion in kill cursors, continuing" << endl; ss << " exception " + e.toString(); } } else { out() << " operation isn't supported: " << m.data->operation() << endl; currentOp.active = false; assert(false); } } ms = t.millis(); log = log || (logLevel >= 2 && ++ctr % 512 == 0); DEV log = true; if ( log || ms > logThreshold ) { ss << ' ' << t.millis() << "ms"; out() << ss.str().c_str() << endl; } Database *database = cc().database(); if ( database && database->profile >= 1 ) { if ( database->profile >= 2 || ms >= 100 ) { // profile it profile(ss.str().c_str()+20/*skip ts*/, ms); } } currentOp.active = false; return true; }
bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthenticationInfo *ai = cc().getAuthenticationInfo(); ai->logout(dbname); return true; }
bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { log(1) << " authenticate: " << cmdObj << endl; string user = cmdObj.getStringField("user"); string key = cmdObj.getStringField("key"); string received_nonce = cmdObj.getStringField("nonce"); if( user.empty() || key.empty() || received_nonce.empty() ) { 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; } stringstream digestBuilder; { nonce *ln = lastNonce.release(); digestBuilder << hex << *ln; if( ln == 0 || digestBuilder.str() != received_nonce ) { 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; } } md5digest d; { string pwd = userObj.getStringField("pwd"); digestBuilder << user << pwd; string done = digestBuilder.str(); md5_state_t st; md5_init(&st); md5_append(&st, (const md5_byte_t *) done.c_str(), done.size()); md5_finish(&st, d); } string computed = digestToString( d ); if ( key != computed ){ log() << "auth: key mismatch " << user << ", ns:" << ns << '\n'; errmsg = "auth fails"; return false; } AuthenticationInfo *ai = authInfo.get(); assert( ai ); ai->authorize(database->name.c_str()); return true; }
void Command::execCommandClientBasic(Command * c , ClientBasic& client, int queryOptions, const char *ns, BSONObj& cmdObj, BSONObjBuilder& result, bool fromRepl ) { verify(c); AuthenticationInfo *ai = client.getAuthenticationInfo(); std::string dbname = nsToDatabase(ns); // Access control checks if (!noauth) { std::vector<Privilege> privileges; c->addRequiredPrivileges(dbname, cmdObj, &privileges); AuthorizationManager* authManager = client.getAuthorizationManager(); if (c->requiresAuth() && (!authManager->checkAuthForPrivileges(privileges).isOK() || !ai->isAuthorizedForLock(dbname, c->locktype()))) { result.append("note", str::stream() << "not authorized for command: " << c->name << " on database " << dbname); appendCommandStatus(result, false, "unauthorized"); return; } } if (c->adminOnly() && c->localHostOnlyIfNoAuth(cmdObj) && noauth && !ai->isLocalHost()) { log() << "command denied: " << cmdObj.toString() << endl; appendCommandStatus(result, false, "unauthorized: this command must run from localhost when running db " "without auth"); return; } if (c->adminOnly() && !startsWith(ns, "admin.")) { log() << "command denied: " << cmdObj.toString() << endl; appendCommandStatus(result, false, "access denied - use admin db"); return; } // End of access control checks if (cmdObj.getBoolField("help")) { stringstream help; help << "help for: " << c->name << " "; c->help( help ); result.append( "help" , help.str() ); result.append( "lockType" , c->locktype() ); appendCommandStatus(result, true, ""); return; } std::string errmsg; bool ok; try { ok = c->run( dbname , cmdObj, queryOptions, errmsg, result, false ); } catch (DBException& e) { ok = false; int code = e.getCode(); if (code == RecvStaleConfigCode) { // code for StaleConfigException throw; } stringstream ss; ss << "exception: " << e.what(); errmsg = ss.str(); result.append( "code" , code ); } appendCommandStatus(result, ok, errmsg); }
bool CmdLogout::run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthenticationInfo *ai = ClientInfo::get()->getAuthenticationInfo(); ai->logout(dbname); return true; }
bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { // database->name is the one we are logging out... AuthenticationInfo *ai = cc().getAuthenticationInfo(); ai->logout(nsToDatabase(ns)); return true; }
bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { log(1) << " authenticate: " << cmdObj << endl; string user = cmdObj.getStringField("user"); string key = cmdObj.getStringField("key"); string received_nonce = cmdObj.getStringField("nonce"); if( user.empty() || key.empty() || received_nonce.empty() ) { log() << "field missing/wrong type in received authenticate command " << cc().database()->name << endl; errmsg = "auth fails"; sleepmillis(10); return false; } stringstream digestBuilder; { bool reject = false; nonce *ln = lastNonce.release(); if ( ln == 0 ) { reject = true; } else { digestBuilder << hex << *ln; reject = digestBuilder.str() != received_nonce; } if ( reject ) { log() << "auth: bad nonce received or getnonce not called. could be a driver bug or a security attack. db:" << cc().database()->name << endl; errmsg = "auth fails"; sleepmillis(30); return false; } } static BSONObj userPattern = fromjson("{\"user\":1}"); string systemUsers = cc().database()->name + ".system.users"; OCCASIONALLY Helpers::ensureIndex(systemUsers.c_str(), userPattern, false, "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 << endl; errmsg = "auth fails"; return false; } } md5digest d; { string pwd = userObj.getStringField("pwd"); digestBuilder << user << pwd; string done = digestBuilder.str(); md5_state_t st; md5_init(&st); md5_append(&st, (const md5_byte_t *) done.c_str(), done.size()); md5_finish(&st, d); } string computed = digestToString( d ); if ( key != computed ){ log() << "auth: key mismatch " << user << ", ns:" << ns << endl; errmsg = "auth fails"; return false; } AuthenticationInfo *ai = cc().getAuthenticationInfo(); if ( userObj[ "readOnly" ].isBoolean() && userObj[ "readOnly" ].boolean() ) { if ( readLockSupported() ){ ai->authorizeReadOnly( cc().database()->name.c_str() ); } else { log() << "warning: old version of boost, read-only users not supported" << endl; ai->authorize( cc().database()->name.c_str() ); } } else { ai->authorize( cc().database()->name.c_str() ); } return true; }
// // Test local authentication // void testLocalAuthSuccess() { String authHeader; AuthenticationManager authManager; AuthenticationInfo* authInfo = new AuthenticationInfo(true); // Test valid header authHeader.append(localHeader); authHeader.append("\""); authHeader.append(testUser); authHeader.append("\""); String respHeader = authManager.getPegasusAuthResponseHeader(authHeader, authInfo); if (verbose) cout << "RespHeader: " << respHeader << endl; Uint32 startQuote = respHeader.find(0, '"'); PEGASUS_TEST_ASSERT(startQuote != PEG_NOT_FOUND); Uint32 endQuote = respHeader.find(startQuote + 1, '"'); PEGASUS_TEST_ASSERT(endQuote != PEG_NOT_FOUND); String filePath = respHeader.subString( startQuote + 1, (endQuote - startQuote - 1)); PEGASUS_TEST_ASSERT(filePath.size() != 0); authHeader.clear(); authHeader.append(localHeader); authHeader.append("\""); authHeader.append(testUser); authHeader.append(":"); authHeader.append(filePath); authHeader.append(":"); authHeader.append(authInfo->getLocalAuthSecret()); authHeader.append("\""); if (verbose) cout << "Local Resp AuthHeader: " << authHeader << endl; Boolean authenticated; // test case looks for success, initialize with failure AuthenticationStatus authStatus(AUTHSC_UNAUTHORIZED); authStatus = authManager.performPegasusAuthentication(authHeader, authInfo); authenticated = authStatus.isSuccess(); // // remove the auth file created for this user request // if (FileSystem::exists(filePath)) { FileSystem::removeFile(filePath); } if (verbose) { cout << "Local Authentication of User " + testUser + " returned with: "; cout << authenticated << endl; } delete authInfo; PEGASUS_TEST_ASSERT(authenticated); }