// ----------------------------------------------------------------------------- // CSdpOriginField::ExternalizeL // Externalizes the field back to string // ----------------------------------------------------------------------------- // void CSdpOriginField::ExternalizeL( RWriteStream& aStream ) const { __TEST_INVARIANT; // <username> aStream.WriteUint32L( UserName().Length() ); aStream.WriteL( UserName(), UserName().Length() ); // <session id> aStream.WriteUint32L( OriginFieldPtrs().SessionId().Length() ); aStream.WriteL( OriginFieldPtrs().SessionId(), OriginFieldPtrs().SessionId().Length() ); // <version> aStream.WriteUint32L( OriginFieldPtrs().SessionVersion().Length() ); aStream.WriteL( OriginFieldPtrs().SessionVersion(), OriginFieldPtrs().SessionVersion().Length() ); // <network type> aStream.WriteUint32L( iNetType.DesC().Length() ); aStream.WriteL( iNetType.DesC() ); // <address type> aStream.WriteUint32L( iAddressType.DesC().Length() ); aStream.WriteL( iAddressType.DesC() ); // <address> aStream.WriteUint32L( iAddress.Length() ); aStream.WriteL( iAddress ); }
// ----------------------------------------------------------------------------- // CSdpOriginField::CloneL // Creates an exact copy of the origin field // ----------------------------------------------------------------------------- // EXPORT_C CSdpOriginField* CSdpOriginField::CloneL() const { __TEST_INVARIANT; CSdpOriginField* obj = 0; if ( InetAddress() ) { // Clones instance with TInetAddr TInetAddr addr( *InetAddress() ); obj = CSdpOriginField::NewLC( UserName(), KDummyValue, KDummyValue, addr ); } else { // Clones instance with Internet address as a standard string obj = CSdpOriginField::NewLC( UserName(), KDummyValue, KDummyValue, iNetType, iAddressType, Address() ); } // Set the real values obj->OriginFieldPtrs().SetSessionIdL( OriginFieldPtrs().SessionId() ); obj->OriginFieldPtrs().SetSessionVersionL( OriginFieldPtrs().SessionVersion() ); CleanupStack::Pop( obj ); __ASSERT_DEBUG( *this == *obj, User::Panic( KSdpCodecPanicCat, KSdpCodecPanicInternal ) ); return obj; }
StatusWith<bool> SaslPLAINServerConversation::step(StringData inputData, std::string* outputData) { // Expecting user input on the form: user\0user\0pwd std::string input = inputData.toString(); std::string pwd = ""; try { _user = input.substr(0, inputData.find('\0')); pwd = input.substr(inputData.find('\0', _user.size() + 1) + 1); } catch (std::out_of_range& exception) { return StatusWith<bool>(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "Incorrectly formatted PLAIN client message"); } User* userObj; // The authentication database is also the source database for the user. Status status = _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().acquireUser( _saslAuthSession->getOpCtxt(), UserName(_user, _saslAuthSession->getAuthenticationDatabase()), &userObj); if (!status.isOK()) { return StatusWith<bool>(status); } const User::CredentialData creds = userObj->getCredentials(); _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().releaseUser(userObj); std::string authDigest = createPasswordDigest(_user, pwd); if (!creds.password.empty()) { // Handle schemaVersion26Final (MONGODB-CR/SCRAM mixed mode) if (authDigest != creds.password) { return StatusWith<bool>(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "Incorrect user name or password"); } } else { // Handle schemaVersion28SCRAM (SCRAM only mode) unsigned char storedKey[scram::hashSize]; unsigned char serverKey[scram::hashSize]; scram::generateSecrets( authDigest, reinterpret_cast<const unsigned char*>(base64::decode(creds.scram.salt).c_str()), 16, creds.scram.iterationCount, storedKey, serverKey); if (creds.scram.storedKey != base64::encode(reinterpret_cast<const char*>(storedKey), scram::hashSize)) { return StatusWith<bool>(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "Incorrect user name or password"); } } *outputData = ""; return StatusWith<bool>(true); }
bool CmdSaslStart::run(OperationContext* txn, const std::string& db, BSONObj& cmdObj, int options, std::string& ignored, BSONObjBuilder& result) { Client* client = Client::getCurrent(); AuthenticationSession::set(client, std::unique_ptr<AuthenticationSession>()); std::string mechanism; if (!extractMechanism(cmdObj, &mechanism).isOK()) { return false; } SaslAuthenticationSession* session = SaslAuthenticationSession::create(AuthorizationSession::get(client), db, mechanism); std::unique_ptr<AuthenticationSession> sessionGuard(session); session->setOpCtxt(txn); Status status = doSaslStart(client, session, db, cmdObj, &result); appendCommandStatus(result, status); if (session->isDone()) { audit::logAuthentication(client, session->getMechanism(), UserName(session->getPrincipalId(), db), status.code()); } else { AuthenticationSession::swap(client, sessionGuard); } return status.isOK(); }
bool CmdSaslStart::run(OperationContext* txn, const std::string& db, BSONObj& cmdObj, int options, std::string& ignored, BSONObjBuilder& result, bool fromRepl) { ClientBasic* client = ClientBasic::getCurrent(); client->resetAuthenticationSession(NULL); SaslAuthenticationSession* session = SaslAuthenticationSession::create(client->getAuthorizationSession()); boost::scoped_ptr<AuthenticationSession> sessionGuard(session); session->setOpCtxt(txn); Status status = doSaslStart(session, db, cmdObj, &result); addStatus(status, &result); if (session->isDone()) { audit::logAuthentication( client, session->getMechanism(), UserName(session->getPrincipalId(), db), status.code()); } else { client->swapAuthenticationSession(sessionGuard); } return status.isOK(); }
Status parseAndValidateRemoveUserCommand(const BSONObj& cmdObj, const std::string& dbname, UserName* parsedUserName, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("removeUser"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "removeUser", validFieldNames); if (!status.isOK()) { return status; } std::string user; status = bsonExtractStringField(cmdObj, "removeUser", &user); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } *parsedUserName = UserName(user, dbname); return Status::OK(); }
DatabaseTagTestFixtureClass() : DatabaseTestFixtureClass("database_tag") , DatabaseTag() { DatabaseTag.Schema = UNICODE_STRING_SIMPLE("database_tag"); DatabaseTag.Host = UNICODE_STRING_SIMPLE("127.0.0.1"); DatabaseTag.User = t4p::CharToIcu(UserName().c_str()); DatabaseTag.Password = t4p::CharToIcu(Password().c_str()); }
bool TCred::CanControl(TCred &cred) const { if (IsRootUser() || Uid == cred.Uid) return true; if (cred.IsMemberOf(PORTO_CONT_GROUP_NAME)) return true; return cred.IsMemberOf(UserName(Uid) + CONT_SUFFIX); }
bool CmdAuthenticate::authenticateX509(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result) { if(dbname != "$external") { errmsg = "X.509 authentication must always use the $external database."; result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } std::string user = cmdObj.getStringField("user"); ClientBasic *client = ClientBasic::getCurrent(); AuthorizationSession* authorizationSession = client->getAuthorizationSession(); StringData subjectName = client->port()->getX509SubjectName(); if (user != subjectName) { errmsg = "There is no x.509 client certificate matching the user."; result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } else { StringData srvSubjectName = getSSLManager()->getSubjectName(); StringData srvClusterId = srvSubjectName.substr(0, srvSubjectName.find("/CN")+1); StringData peerClusterId = subjectName.substr(0, subjectName.find("/CN")+1); // Handle internal cluster member if (srvClusterId == peerClusterId) { authorizationSession->grantInternalAuthorization(UserName(user, "$external")); } // Handle normal client authentication else { Principal* principal = new Principal(UserName(user, "$external")); principal->setImplicitPrivilegeAcquisition(true); authorizationSession->addAuthorizedPrincipal(principal); } result.append( "dbname" , dbname ); result.append( "user" , user ); return true; } }
Status parseUserRoleManipulationCommand(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, AuthorizationManager* authzManager, UserName* parsedUserName, vector<RoleName>* parsedRoleNames, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } std::string userNameStr; status = bsonExtractStringField(cmdObj, cmdName, &userNameStr); if (!status.isOK()) { return status; } *parsedUserName = UserName(userNameStr, dbname); BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } status = _extractRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, authzManager, parsedRoleNames); if (!status.isOK()) { return status; } if (!parsedRoleNames->size()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << cmdName << " command requires a non-empty" << " roles array"); } return Status::OK(); }
MysqlResourceFinderFixtureClass() : DatabaseTestFixtureClass("sql_resource_finder") , SqliteTestFixtureClass(t4p::ResourceSqlSchemaAsset()) , DatabaseTag() , Fetcher(SqliteTestFixtureClass::Session) , Finder(SqliteTestFixtureClass::Session) { DatabaseTag.Driver = t4p::DatabaseTagClass::MYSQL; DatabaseTag.Schema = UNICODE_STRING_SIMPLE("sql_resource_finder"); // user name, pwd are #defines come from the premake script premake_opts.lua DatabaseTag.Host = UNICODE_STRING_SIMPLE("127.0.0.1"); DatabaseTag.User = t4p::CharToIcu(UserName().c_str()); DatabaseTag.Password = t4p::CharToIcu(Password().c_str()); }
MONGO_INITIALIZER_WITH_PREREQUISITES(SetupInternalSecurityUser, MONGO_NO_PREREQUISITES)( InitializerContext* context) { User* user = new User(UserName("__system", "local")); user->incrementRefCount(); // Pin this user so the ref count never drops below 1. ActionSet allActions; allActions.addAllActions(); PrivilegeVector privileges; RoleGraph::generateUniversalPrivileges(&privileges); user->addPrivileges(privileges); internalSecurity.user = user; return Status::OK(); }
bool CmdSaslContinue::run(OperationContext* txn, const std::string& db, BSONObj& cmdObj, int options, std::string& ignored, BSONObjBuilder& result, bool fromRepl) { ClientBasic* client = ClientBasic::getCurrent(); boost::scoped_ptr<AuthenticationSession> sessionGuard(NULL); client->swapAuthenticationSession(sessionGuard); if (!sessionGuard || sessionGuard->getType() != AuthenticationSession::SESSION_TYPE_SASL) { addStatus(Status(ErrorCodes::ProtocolError, "No SASL session state found"), &result); return false; } SaslAuthenticationSession* session = static_cast<SaslAuthenticationSession*>(sessionGuard.get()); // Authenticating the __system@local user to the admin database on mongos is required // by the auth passthrough test suite. if (session->getAuthenticationDatabase() != db && !Command::testCommandsEnabled) { addStatus(Status(ErrorCodes::ProtocolError, "Attempt to switch database target during SASL authentication."), &result); return false; } session->setOpCtxt(txn); Status status = doSaslContinue(session, cmdObj, &result); addStatus(status, &result); if (session->isDone()) { audit::logAuthentication( client, session->getMechanism(), UserName(session->getPrincipalId(), db), status.code()); } else { client->swapAuthenticationSession(sessionGuard); } return status.isOK(); }
StatusWith<bool> SaslPLAINServerConversation::step(const StringData& inputData, std::string* outputData) { // Expecting user input on the form: user\0user\0pwd std::string input = inputData.toString(); std::string pwd = ""; try { _user = input.substr(0, inputData.find('\0')); pwd = input.substr(inputData.find('\0', _user.size()+1)+1); } catch (std::out_of_range& exception) { return StatusWith<bool>(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "Incorrectly formatted PLAIN client message"); } User* userObj; // The authentication database is also the source database for the user. Status status = _saslAuthSession->getAuthorizationSession()->getAuthorizationManager(). acquireUser(_saslAuthSession->getOpCtxt(), UserName(_user, _saslAuthSession->getAuthenticationDatabase()), &userObj); if (!status.isOK()) { return StatusWith<bool>(status); } const User::CredentialData creds = userObj->getCredentials(); _saslAuthSession->getAuthorizationSession()->getAuthorizationManager(). releaseUser(userObj); std::string authDigest = createPasswordDigest(_user, pwd); if (authDigest != creds.password) { return StatusWith<bool>(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "Incorrect user name or password"); } *outputData = ""; return StatusWith<bool>(true); }
bool CmdSaslContinue::run(OperationContext* opCtx, const std::string& db, const BSONObj& cmdObj, BSONObjBuilder& result) { Client* client = Client::getCurrent(); std::unique_ptr<AuthenticationSession> sessionGuard; AuthenticationSession::swap(client, sessionGuard); if (!sessionGuard || sessionGuard->getType() != AuthenticationSession::SESSION_TYPE_SASL) { return appendCommandStatus( result, Status(ErrorCodes::ProtocolError, "No SASL session state found")); } SaslAuthenticationSession* session = static_cast<SaslAuthenticationSession*>(sessionGuard.get()); // Authenticating the __system@local user to the admin database on mongos is required // by the auth passthrough test suite. if (session->getAuthenticationDatabase() != db && !Command::testCommandsEnabled) { return appendCommandStatus( result, Status(ErrorCodes::ProtocolError, "Attempt to switch database target during SASL authentication.")); } session->setOpCtxt(opCtx); Status status = doSaslContinue(client, session, cmdObj, &result); appendCommandStatus(result, status); if (session->isDone()) { audit::logAuthentication(client, session->getMechanism(), UserName(session->getPrincipalId(), db), status.code()); } else { AuthenticationSession::swap(client, sessionGuard); } return status.isOK(); }
// ----------------------------------------------------------------------------- // CSdpOriginField::operator == // Checks if two origin fields are equal // ----------------------------------------------------------------------------- // EXPORT_C TBool CSdpOriginField::operator == ( const CSdpOriginField& aObj) const { __TEST_INVARIANT; TBool equalFields = EFalse; // Check that username, session ID and address type match before // going to internet address if ( ( UserName().CompareF( aObj.UserName() ) == 0 ) && ( SessionId() == aObj.SessionId() ) && ( AddressType() == aObj.AddressType() ) && ( Version() == aObj.Version() ) && ( NetType() == aObj.NetType() ) ) { if ( InetAddress() && aObj.InetAddress() ) { if ( (*InetAddress()).Match( *aObj.InetAddress() ) ) { equalFields = ETrue; } } else if ( !InetAddress() && !aObj.InetAddress() ) { if ( iAddress.CompareF( aObj.Address() ) == 0 ) { equalFields = ETrue; } } else { // These two are not the same } } return equalFields; }
bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { UpdateUserArgs args; Status status = _parseAndValidateInput(cmdObj, &args); if (!status.isOK()) { addStatus(status, result); return false; } // TODO: This update will have to change once we're using the new v2 user // storage format. BSONObjBuilder setBuilder; if (args.hasPassword) { std::string password = DBClientWithCommands::createPasswordDigest( args.userName, args.clearTextPassword); setBuilder.append("pwd", password); } if (args.hasExtraData) { setBuilder.append("extraData", args.extraData); } BSONObj updateObj = BSON("$set" << setBuilder.obj()); status = getGlobalAuthorizationManager()->updatePrivilegeDocument( UserName(args.userName, dbname), updateObj); if (!status.isOK()) { addStatus(status, result); return false; } return true; }
Status parseCreateOrUpdateUserCommands(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, CreateOrUpdateUserArgs* parsedArgs) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("customData"); validFieldNames.insert("digestPassword"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, &parsedArgs->writeConcern); if (!status.isOK()) { return status; } BSONObjBuilder userObjBuilder; // Parse user name std::string userName; status = bsonExtractStringField(cmdObj, cmdName, &userName); if (!status.isOK()) { return status; } parsedArgs->userName = UserName(userName, dbname); // Parse password if (cmdObj.hasField("pwd")) { std::string password; status = bsonExtractStringField(cmdObj, "pwd", &password); if (!status.isOK()) { return status; } if (password.empty()) { return Status(ErrorCodes::BadValue, "User passwords must not be empty"); } bool digestPassword; // True if the server should digest the password status = bsonExtractBooleanFieldWithDefault(cmdObj, "digestPassword", true, &digestPassword); if (!status.isOK()) { return status; } if (digestPassword) { parsedArgs->hashedPassword = auth::createPasswordDigest(userName, password); } else { parsedArgs->hashedPassword = password; } parsedArgs->hasHashedPassword = true; } // Parse custom data if (cmdObj.hasField("customData")) { BSONElement element; status = bsonExtractTypedField(cmdObj, "customData", Object, &element); if (!status.isOK()) { return status; } parsedArgs->customData = element.Obj(); parsedArgs->hasCustomData = true; } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } status = parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, &parsedArgs->roles); if (!status.isOK()) { return status; } parsedArgs->hasRoles = true; } return Status::OK(); }
Status parseCreateOrUpdateUserCommands(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, CreateOrUpdateUserArgs* parsedArgs) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("customData"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, &parsedArgs->writeConcern); if (!status.isOK()) { return status; } BSONObjBuilder userObjBuilder; // Parse user name std::string userName; status = bsonExtractStringField(cmdObj, cmdName, &userName); if (!status.isOK()) { return status; } parsedArgs->userName = UserName(userName, dbname); // Parse password if (cmdObj.hasField("pwd")) { std::string clearTextPassword; status = bsonExtractStringField(cmdObj, "pwd", &clearTextPassword); if (!status.isOK()) { return status; } parsedArgs->hashedPassword = auth::createPasswordDigest(userName, clearTextPassword); parsedArgs->hasHashedPassword = true; } // Parse custom data if (cmdObj.hasField("customData")) { BSONElement element; status = bsonExtractTypedField(cmdObj, "customData", Object, &element); if (!status.isOK()) { return status; } parsedArgs->customData = element.Obj(); parsedArgs->hasCustomData = true; } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } status = _extractRoleDataFromBSONArray(rolesElement, dbname, &parsedArgs->roles); if (!status.isOK()) { return status; } parsedArgs->hasRoles = true; } return Status::OK(); }
/* ******************************************************************* * Function: int BehaviourFunction( const CKBehaviorContext& behaviorContext ) * * Description : The execution function is the function that will be called * during the process loop of the behavior engine, if the behavior * is defined as using an execution function. This function is not * called if the behavior is defined as a graph. This function is the * heart of the behavior: it should compute the essence of the behavior, * in an incremental way. The minimum amount of computing should be * done at each call, to leave time for the other behaviors to run. * The function receives the delay in milliseconds that has elapsed * since the last behavioral process, and should rely on this value to * manage the amount of effect it has on its computation, if the effect * of this computation relies on time. * * Parameters : * behaviourContext r Behavior context reference, which gives access to * frequently used global objects ( context, level, manager, etc... ) * * Returns : int, If it is done, it should return CKBR_OK. If it returns * CKBR_ACTIVATENEXTFRAME, the behavior will again be called * during the next process loop. * ******************************************************************* */ int GBLPFCreate::BehaviourFunction( const CKBehaviorContext& behaviorContext ) { CKBehavior *behaviour=behaviorContext.Behavior; CKContext *context = behaviorContext.Context; CGBLCOError returnValue(CGBLCOError::EGBLCOErrorType::GBLCO_OK); CKBOOL newTeam = true; CKERROR check; behaviour->ActivateInput(EGBLCreateBehInputs::In, false); //newTeam = behaviour->IsInputParameterEnabled(EGBLCreateParamInputs::Teamname); CGBLUserID NewPlayerId; CGBLTeamID TeamId; CGBLProfileManager *pm = (CGBLProfileManager *)context->GetManagerByGuid(GBLProfileManagerGUID); int buf; check = behaviour->GetInputParameterValue(EGBLCreateParamInputs::LAEID, &buf); if(check != CK_OK|| buf==0) { newTeam = false; } CGBLLAEID LAEID(buf); XString TeamName((CKSTRING)behaviour->GetInputParameterReadDataPtr(EGBLCreateParamInputs::Teamname)); CGBLProfileManager::EGBLUserType userType; behaviour->GetInputParameterValue(EGBLCreateParamInputs::Type, &userType); XString UserName((CKSTRING) behaviour->GetInputParameterReadDataPtr(EGBLCreateParamInputs::Username)); if(newTeam) { returnValue = pm->CreateTeamProfile(&TeamId, LAEID, TeamName); } else { returnValue = pm->CreatePlayerProfile(&NewPlayerId, userType, UserName); } if ((int)returnValue == CGBLCOError::EGBLCOErrorType::GBLCO_OK) { if (newTeam)//activate output with TeamId { behaviour->SetOutputParameterValue(EGBLCreateParamOutputs::ProfileId, &TeamId); } else //acitvate output with PlayerId { behaviour->SetOutputParameterValue(EGBLCreateParamOutputs::ProfileId, &NewPlayerId); } behaviour->ActivateOutput(EGBLCreateBehOutputs::Success, true); } else { CKParameterOut *pOut = behaviour->GetOutputParameter(EGBLCreateParamOutputs::ErrorCode); CGBLCOError::EGBLCOErrorType tType = CGBLCOError::EGBLCOErrorType::GBLCO_OK ; switch((CGBLCOError::EGBLCOErrorType)returnValue) { case 0: tType = CGBLCOError::EGBLCOErrorType::GBLCO_OK; break; case 1: tType = CGBLCOError::EGBLCOErrorType::GBLCO_FATAL; break; case 2: tType = CGBLCOError::EGBLCOErrorType::GBLCO_LOCAL; break; case 3: tType = CGBLCOError::EGBLCOErrorType::GBLCO_LOCAL; break; } const char*errorString = returnValue; TGBLError::SetTGBLError(pOut, tType,returnValue, (CKSTRING)errorString); //behaviour->SetOutputParameterValue(EGBLCreateParamOutputs::ErrorCode, &returnValue); behaviour->ActivateOutput(EGBLCreateBehOutputs::Error, true); } return CKBR_OK; }
/* * Parse client-first-message of the form: * n,a=authzid,n=encoded-username,r=client-nonce * * Generate server-first-message on the form: * r=client-nonce|server-nonce,s=user-salt,i=iteration-count * * NOTE: we are ignoring the authorization ID part of the message */ StatusWith<bool> SaslSCRAMSHA1ServerConversation::_firstStep(std::vector<string>& input, std::string* outputData) { #ifndef MONGO_SSL return StatusWith<bool>(ErrorCodes::InternalError, "The server is not compiled with SSL support"); #else std::string authzId = ""; if (input.size() == 4) { /* The second entry a=authzid is optional. If provided it will be * validated against the encoded username. * * The two allowed input forms are: * n,,n=encoded-username,r=client-nonce * n,a=authzid,n=encoded-username,r=client-nonce */ if (!str::startsWith(input[1], "a=") || input[1].size() < 3) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 authzid: " << input[1]); } authzId = input[1].substr(2); input.erase(input.begin() + 1); } if (input.size() != 3) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect number of arguments for first SCRAM-SHA-1 client message, got " << input.size() << " expected 4"); } else if (input[0] != "n") { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 client message prefix: " << input[0]); } else if (!str::startsWith(input[1], "n=") || input[1].size() < 3) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 user name: " << input[1]); } else if(!str::startsWith(input[2], "r=") || input[2].size() < 6) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "Incorrect SCRAM-SHA-1 client nonce: " << input[2]); } // add client-first-message-bare to _authMessage _authMessage += input[1] + "," + input[2] + ","; _user = input[1].substr(2); if (!authzId.empty() && _user != authzId) { return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() << "SCRAM-SHA-1 user name " << _user << " does not match authzid " << authzId); } decodeSCRAMUsername(_user); std::string clientNonce = input[2].substr(2); // The authentication database is also the source database for the user. User* userObj; Status status = _saslAuthSession->getAuthorizationSession()->getAuthorizationManager(). acquireUser(_saslAuthSession->getOpCtxt(), UserName(_user, _saslAuthSession->getAuthenticationDatabase()), &userObj); if (!status.isOK()) { return StatusWith<bool>(status); } _creds = userObj->getCredentials(); _saslAuthSession->getAuthorizationSession()->getAuthorizationManager(). releaseUser(userObj); // Generate SCRAM credentials on the fly for mixed MONGODB-CR/SCRAM mode. if (_creds.scram.salt.empty() && !_creds.password.empty()) { BSONObj scramCreds = scram::generateCredentials(_creds.password); _creds.scram.iterationCount = scramCreds["iterationCount"].Int(); _creds.scram.salt = scramCreds["salt"].String(); _creds.scram.storedKey = scramCreds["storedKey"].String(); _creds.scram.serverKey = scramCreds["serverKey"].String(); } // Generate server-first-message // Create text-based nonce as base64 encoding of a binary blob of length multiple of 3 const int nonceLenQWords = 3; uint64_t binaryNonce[nonceLenQWords]; scoped_ptr<SecureRandom> sr(SecureRandom::create()); binaryNonce[0] = sr->nextInt64(); binaryNonce[1] = sr->nextInt64(); binaryNonce[2] = sr->nextInt64(); _nonce = clientNonce + base64::encode(reinterpret_cast<char*>(binaryNonce), sizeof(binaryNonce)); StringBuilder sb; sb << "r=" << _nonce << ",s=" << _creds.scram.salt << ",i=" << _creds.scram.iterationCount; *outputData = sb.str(); // add server-first-message to authMessage _authMessage += *outputData + ","; return StatusWith<bool>(false); #endif // MONGO_SSL }
Status parseAndValidateUpdateUserCommand(const BSONObj& cmdObj, const std::string& dbname, AuthorizationManager* authzManager, BSONObj* parsedUpdateObj, UserName* parsedUserName, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("updateUser"); validFieldNames.insert("customData"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "updateUser", validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } BSONObjBuilder updateSetBuilder; // Parse user name std::string userName; status = bsonExtractStringField(cmdObj, "updateUser", &userName); if (!status.isOK()) { return status; } *parsedUserName = UserName(userName, dbname); // Parse password if (cmdObj.hasField("pwd")) { std::string clearTextPassword; status = bsonExtractStringField(cmdObj, "pwd", &clearTextPassword); if (!status.isOK()) { return status; } std::string password = auth::createPasswordDigest(userName, clearTextPassword); updateSetBuilder.append("credentials.MONGODB-CR", password); } // Parse custom data if (cmdObj.hasField("customData")) { BSONElement element; status = bsonExtractTypedField(cmdObj, "customData", Object, &element); if (!status.isOK()) { return status; } updateSetBuilder.append("customData", element.Obj()); } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; Status status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } BSONArray modifiedRolesObj; status = _validateAndModifyRolesArray(rolesElement, dbname, authzManager, true, &modifiedRolesObj); if (!status.isOK()) { return status; } updateSetBuilder.append("roles", modifiedRolesObj); } BSONObj updateSet = updateSetBuilder.obj(); if (updateSet.isEmpty()) { return Status(ErrorCodes::UserModificationFailed, "Must specify at least one field to update in updateUser"); } *parsedUpdateObj = BSON("$set" << updateSet); return Status::OK(); }
StatusWith<bool> SaslPLAINServerConversation::step(StringData inputData, std::string* outputData) { if (_saslAuthSession->getAuthenticationDatabase() == "$external") { return Status(ErrorCodes::AuthenticationFailed, "PLAIN mechanism must be used with internal users"); } // Expecting user input on the form: [authz-id]\0authn-id\0pwd std::string input = inputData.toString(); SecureAllocatorAuthDomain::SecureString pwd = ""; try { size_t firstNull = inputData.find('\0'); if (firstNull == std::string::npos) { return Status( ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, missing first NULL delimiter"); } size_t secondNull = inputData.find('\0', firstNull + 1); if (secondNull == std::string::npos) { return Status( ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, missing second NULL delimiter"); } std::string authorizationIdentity = input.substr(0, firstNull); _user = input.substr(firstNull + 1, (secondNull - firstNull) - 1); if (_user.empty()) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, empty username"); } else if (!authorizationIdentity.empty() && authorizationIdentity != _user) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "SASL authorization identity must match authentication identity"); } pwd = SecureAllocatorAuthDomain::SecureString(input.substr(secondNull + 1).c_str()); if (pwd->empty()) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, empty password"); } } catch (std::out_of_range& exception) { return Status(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "Incorrectly formatted PLAIN client message"); } User* userObj; // The authentication database is also the source database for the user. Status status = _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().acquireUser( _saslAuthSession->getOpCtxt(), UserName(_user, _saslAuthSession->getAuthenticationDatabase()), &userObj); if (!status.isOK()) { return StatusWith<bool>(status); } const User::CredentialData creds = userObj->getCredentials(); _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().releaseUser(userObj); std::string authDigest = createPasswordDigest(_user, pwd->c_str()); if (!creds.password.empty()) { // Handle schemaVersion26Final (MONGODB-CR/SCRAM mixed mode) if (authDigest != creds.password) { return StatusWith<bool>(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "Incorrect user name or password"); } } else { // Handle schemaVersion28SCRAM (SCRAM only mode) std::string decodedSalt = base64::decode(creds.scram.salt); scram::SCRAMSecrets secrets = scram::generateSecrets(scram::SCRAMPresecrets( authDigest, std::vector<std::uint8_t>(reinterpret_cast<const std::uint8_t*>(decodedSalt.c_str()), reinterpret_cast<const std::uint8_t*>(decodedSalt.c_str()) + 16), creds.scram.iterationCount)); if (creds.scram.storedKey != base64::encode(reinterpret_cast<const char*>(secrets->storedKey.data()), secrets->storedKey.size())) { return StatusWith<bool>(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "Incorrect user name or password"); } } *outputData = ""; return StatusWith<bool>(true); }
StatusWith<bool> SaslPLAINServerConversation::step(StringData inputData, std::string* outputData) { if (_saslAuthSession->getAuthenticationDatabase() == "$external") { return Status(ErrorCodes::AuthenticationFailed, "PLAIN mechanism must be used with internal users"); } // Expecting user input on the form: [authz-id]\0authn-id\0pwd std::string input = inputData.toString(); SecureAllocatorAuthDomain::SecureString pwd = ""; try { size_t firstNull = inputData.find('\0'); if (firstNull == std::string::npos) { return Status( ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, missing first NULL delimiter"); } size_t secondNull = inputData.find('\0', firstNull + 1); if (secondNull == std::string::npos) { return Status( ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, missing second NULL delimiter"); } std::string authorizationIdentity = input.substr(0, firstNull); _user = input.substr(firstNull + 1, (secondNull - firstNull) - 1); if (_user.empty()) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, empty username"); } else if (!authorizationIdentity.empty() && authorizationIdentity != _user) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "SASL authorization identity must match authentication identity"); } pwd = SecureAllocatorAuthDomain::SecureString(input.substr(secondNull + 1).c_str()); if (pwd->empty()) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, empty password"); } } catch (std::out_of_range&) { return Status(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() << "Incorrectly formatted PLAIN client message"); } User* userObj; // The authentication database is also the source database for the user. Status status = _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().acquireUser( _saslAuthSession->getOpCtxt(), UserName(_user, _saslAuthSession->getAuthenticationDatabase()), &userObj); if (!status.isOK()) { return status; } const auto creds = userObj->getCredentials(); _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().releaseUser(userObj); *outputData = ""; const auto sha256Status = trySCRAM<SHA256Block>(creds, pwd->c_str()); if (!sha256Status.isOK()) { return sha256Status; } if (sha256Status.getValue()) { return true; } const auto authDigest = createPasswordDigest(_user, pwd->c_str()); const auto sha1Status = trySCRAM<SHA1Block>(creds, authDigest); if (!sha1Status.isOK()) { return sha1Status; } if (sha1Status.getValue()) { return true; } return Status(ErrorCodes::AuthenticationFailed, str::stream() << "No credentials available."); }
StatusWith<std::tuple<bool, std::string>> SASLPlainServerMechanism::stepImpl( OperationContext* opCtx, StringData inputData) { if (_authenticationDatabase == "$external") { return Status(ErrorCodes::AuthenticationFailed, "PLAIN mechanism must be used with internal users"); } AuthorizationManager* authManager = AuthorizationManager::get(opCtx->getServiceContext()); // Expecting user input on the form: [authz-id]\0authn-id\0pwd std::string input = inputData.toString(); SecureAllocatorAuthDomain::SecureString pwd = ""; try { size_t firstNull = inputData.find('\0'); if (firstNull == std::string::npos) { return Status( ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, missing first NULL delimiter"); } size_t secondNull = inputData.find('\0', firstNull + 1); if (secondNull == std::string::npos) { return Status( ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, missing second NULL delimiter"); } std::string authorizationIdentity = input.substr(0, firstNull); ServerMechanismBase::_principalName = input.substr(firstNull + 1, (secondNull - firstNull) - 1); if (ServerMechanismBase::_principalName.empty()) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, empty username"); } else if (!authorizationIdentity.empty() && authorizationIdentity != ServerMechanismBase::_principalName) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "SASL authorization identity must match authentication identity"); } pwd = SecureAllocatorAuthDomain::SecureString(input.substr(secondNull + 1).c_str()); if (pwd->empty()) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message, empty password"); } } catch (std::out_of_range&) { return Status(ErrorCodes::AuthenticationFailed, str::stream() << "Incorrectly formatted PLAIN client message"); } // The authentication database is also the source database for the user. auto swUser = authManager->acquireUser( opCtx, UserName(ServerMechanismBase::_principalName, _authenticationDatabase)); if (!swUser.isOK()) { return swUser.getStatus(); } auto userObj = std::move(swUser.getValue()); const auto creds = userObj->getCredentials(); const auto sha256Status = trySCRAM<SHA256Block>(creds, pwd->c_str()); if (!sha256Status.isOK()) { return sha256Status.getStatus(); } if (sha256Status.getValue()) { return std::make_tuple(true, std::string()); } const auto authDigest = createPasswordDigest(ServerMechanismBase::_principalName, pwd->c_str()); const auto sha1Status = trySCRAM<SHA1Block>(creds, authDigest); if (!sha1Status.isOK()) { return sha1Status.getStatus(); } if (sha1Status.getValue()) { return std::make_tuple(true, std::string()); } return Status(ErrorCodes::AuthenticationFailed, str::stream() << "No credentials available."); return std::make_tuple(true, std::string()); }
void WriteBackListener::run() { int secsToSleep = 0; scoped_ptr<ChunkVersion> lastNeededVersion; int lastNeededCount = 0; bool needsToReloadShardInfo = false; while ( ! inShutdown() ) { if ( ! Shard::isAShardNode( _addr ) ) { LOG(1) << _addr << " is not a shard node" << endl; sleepsecs( 60 ); continue; } try { if (needsToReloadShardInfo) { // It's possible this shard was removed Shard::reloadShardInfo(); needsToReloadShardInfo = false; } ScopedDbConnection conn(_addr); BSONObj result; { BSONObjBuilder cmd; cmd.appendOID( "writebacklisten" , &serverID ); // Command will block for data if ( ! conn->runCommand( "admin" , cmd.obj() , result ) ) { result = result.getOwned(); log() << "writebacklisten command failed! " << result << endl; conn.done(); continue; } } conn.done(); LOG(1) << "writebacklisten result: " << result << endl; BSONObj data = result.getObjectField( "data" ); if ( data.getBoolField( "writeBack" ) ) { string ns = data["ns"].valuestrsafe(); ConnectionIdent cid( "" , 0 ); OID wid; if ( data["connectionId"].isNumber() && data["id"].type() == jstOID ) { string s = ""; if ( data["instanceIdent"].type() == String ) s = data["instanceIdent"].String(); cid = ConnectionIdent( s , data["connectionId"].numberLong() ); wid = data["id"].OID(); } else { warning() << "mongos/mongod version mismatch (1.7.5 is the split)" << endl; } int len; // not used, but needed for next call Message msg( (void*)data["msg"].binData( len ) , false ); massert( 10427 , "invalid writeback message" , msg.header()->valid() ); DBConfigPtr db = grid.getDBConfig( ns ); ChunkVersion needVersion = ChunkVersion::fromBSON( data, "version" ); // // TODO: Refactor the sharded strategy to correctly handle all sharding state changes itself, // we can't rely on WBL to do this for us b/c anything could reset our state in-between. // We should always reload here for efficiency when possible, but staleness is also caught in the // loop below. // ChunkManagerPtr manager; ShardPtr primary; db->getChunkManagerOrPrimary( ns, manager, primary ); ChunkVersion currVersion; if( manager ) currVersion = manager->getVersion(); LOG(1) << "connectionId: " << cid << " writebackId: " << wid << " needVersion : " << needVersion.toString() << " mine : " << currVersion.toString() << endl; LOG(1) << msg.toString() << endl; // // We should reload only if we need to update our version to be compatible *and* we // haven't already done so. This avoids lots of reloading when we remove/add a sharded collection // bool alreadyReloaded = lastNeededVersion && lastNeededVersion->isEquivalentTo( needVersion ); if( alreadyReloaded ){ LOG(1) << "wbl already reloaded config information for version " << needVersion << ", at version " << currVersion << endl; } else if( lastNeededVersion ) { log() << "new version change detected to " << needVersion.toString() << ", " << lastNeededCount << " writebacks processed at " << lastNeededVersion->toString() << endl; lastNeededCount = 0; } // // Set our lastNeededVersion for next time // lastNeededVersion.reset( new ChunkVersion( needVersion ) ); lastNeededCount++; // // Determine if we should reload, if so, reload // bool shouldReload = ! needVersion.isWriteCompatibleWith( currVersion ) && ! alreadyReloaded; if( shouldReload && currVersion.isSet() && needVersion.isSet() && currVersion.hasCompatibleEpoch( needVersion ) ) { // // If we disagree about versions only, reload the chunk manager // db->getChunkManagerIfExists( ns, true ); } else if( shouldReload ){ // // If we disagree about anything else, reload the full db // warning() << "reloading config data for " << db->getName() << ", " << "wanted version " << needVersion.toString() << " but currently have version " << currVersion.toString() << endl; db->reload(); } // do request and then call getLastError // we have to call getLastError so we can return the right fields to the user if they decide to call getLastError BSONObj gle; int attempts = 0; while ( true ) { attempts++; try { Request r( msg , 0 ); r.init(); r.d().reservedField() |= Reserved_FromWriteback; ClientInfo * ci = r.getClientInfo(); if (AuthorizationManager::isAuthEnabled()) { ci->getAuthorizationSession()->grantInternalAuthorization( UserName("_writebackListener", "local")); } ci->noAutoSplit(); r.process( attempts ); ci->newRequest(); // this so we flip prev and cur shards BSONObjBuilder b; string errmsg; if ( ! ci->getLastError( "admin", BSON( "getLastError" << 1 ), b, errmsg, true ) ) { b.appendBool( "commandFailed" , true ); if( ! b.hasField( "errmsg" ) ){ b.append( "errmsg", errmsg ); gle = b.obj(); } else if( errmsg.size() > 0 ){ // Rebuild GLE object with errmsg // TODO: Make this less clumsy by improving GLE interface gle = b.obj(); if( gle["errmsg"].type() == String ){ BSONObj gleNoErrmsg = gle.filterFieldsUndotted( BSON( "errmsg" << 1 ), false ); BSONObjBuilder bb; bb.appendElements( gleNoErrmsg ); bb.append( "errmsg", gle["errmsg"].String() + " ::and:: " + errmsg ); gle = bb.obj().getOwned(); } } } else{ gle = b.obj(); } if ( gle["code"].numberInt() == 9517 ) { log() << "new version change detected, " << lastNeededCount << " writebacks processed previously" << endl; lastNeededVersion.reset(); lastNeededCount = 1; log() << "writeback failed because of stale config, retrying attempts: " << attempts << endl; LOG(1) << "writeback error : " << gle << endl; // // Bringing this in line with the similar retry logic elsewhere // // TODO: Reloading the chunk manager may not help if we dropped a // collection, but we don't actually have that info in the writeback // error // if( attempts <= 2 ){ db->getChunkManagerIfExists( ns, true ); } else{ versionManager.forceRemoteCheckShardVersionCB( ns ); sleepsecs( attempts - 1 ); } uassert( 15884, str::stream() << "Could not reload chunk manager after " << attempts << " attempts.", attempts <= 4 ); continue; } ci->clearSinceLastGetError(); } catch ( DBException& e ) { error() << "error processing writeback: " << e << endl; BSONObjBuilder b; e.getInfo().append( b, "err", "code" ); gle = b.obj(); } break; } { scoped_lock lk( _seenWritebacksLock ); WBStatus& s = _seenWritebacks[cid]; s.id = wid; s.gle = gle; } } else if ( result["noop"].trueValue() ) { // no-op } else { log() << "unknown writeBack result: " << result << endl; } secsToSleep = 0; continue; } catch ( std::exception& e ) { // Attention! Do not call any method that would throw an exception // (or assert) in this block. if ( inShutdown() ) { // we're shutting down, so just clean up return; } log() << "WriteBackListener exception : " << e.what() << endl; needsToReloadShardInfo = true; } catch ( ... ) { log() << "WriteBackListener uncaught exception!" << endl; } secsToSleep++; sleepsecs(secsToSleep); if ( secsToSleep > 10 ) secsToSleep = 0; } log() << "WriteBackListener exiting : address no longer in cluster " << _addr; }
bool CmdAuthenticate::authenticateCR(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result) { string user = cmdObj.getStringField("user"); if (!_areNonceAuthenticateCommandsEnabled) { // SERVER-8461, MONGODB-CR must be enabled for authenticating the internal user, so that // cluster members may communicate with each other. if (dbname != StringData("local", StringData::LiteralTag()) || user != internalSecurity.user) { errmsg = _nonceAuthenticateCommandsDisabledMessage; result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } } 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 " << dbname << endl; errmsg = "auth fails"; sleepmillis(10); result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } stringstream digestBuilder; { bool reject = false; ClientBasic *client = ClientBasic::getCurrent(); AuthenticationSession *session = client->getAuthenticationSession(); if (!session || session->getType() != AuthenticationSession::SESSION_TYPE_MONGO) { reject = true; LOG(1) << "auth: No pending nonce" << endl; } else { nonce64 nonce = static_cast<MongoAuthenticationSession*>(session)->getNonce(); digestBuilder << hex << nonce; reject = digestBuilder.str() != received_nonce; if ( reject ) { LOG(1) << "auth: Authentication failed for " << dbname << '$' << user << endl; } } client->resetAuthenticationSession(NULL); if ( reject ) { log() << "auth: bad nonce received or getnonce not called. could be a driver bug or a security attack. db:" << dbname << endl; errmsg = "auth fails"; sleepmillis(30); result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } } BSONObj userObj; string pwd; Status status = getGlobalAuthorizationManager()->getPrivilegeDocument( dbname, UserName(user, dbname), &userObj); if (!status.isOK()) { log() << status.reason() << std::endl; errmsg = "auth fails"; result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } pwd = userObj["pwd"].String(); md5digest d; { 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:" << dbname << endl; errmsg = "auth fails"; result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } AuthorizationSession* authorizationSession = ClientBasic::getCurrent()->getAuthorizationSession(); Principal* principal = new Principal(UserName(user, dbname)); principal->setImplicitPrivilegeAcquisition(true); authorizationSession->addAuthorizedPrincipal(principal); result.append( "dbname" , dbname ); result.append( "user" , user ); return true; }
const string& GetUserName(void) const { return UserName(); }
Status parseAndValidateUpdateUserCommand(const BSONObj& cmdObj, const std::string& dbname, AuthorizationManager* authzManager, BSONObj* parsedUpdateObj, UserName* parsedUserName) { unordered_set<std::string> validFieldNames; validFieldNames.insert("updateUser"); validFieldNames.insert("customData"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); // Iterate through all fields in command object and make sure there are no unexpected // ones. for (BSONObjIterator iter(cmdObj); iter.more(); iter.next()) { StringData fieldName = (*iter).fieldNameStringData(); if (!validFieldNames.count(fieldName.toString())) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "\"" << fieldName << "\" is not " "a valid argument to createUser"); } } BSONObjBuilder updateSetBuilder; // Parse user name std::string userName; Status status = bsonExtractStringField(cmdObj, "updateUser", &userName); if (!status.isOK()) { return status; } *parsedUserName = UserName(userName, dbname); // Parse password if (cmdObj.hasField("pwd")) { std::string clearTextPassword; status = bsonExtractStringField(cmdObj, "pwd", &clearTextPassword); if (!status.isOK()) { return status; } std::string password = auth::createPasswordDigest(userName, clearTextPassword); updateSetBuilder.append("credentials.MONGODB-CR", password); } // Parse custom data if (cmdObj.hasField("customData")) { BSONElement element; status = bsonExtractTypedField(cmdObj, "customData", Object, &element); if (!status.isOK()) { return status; } updateSetBuilder.append("customData", element.Obj()); } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; Status status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } BSONArray modifiedRolesObj; status = _validateAndModifyRolesArray(rolesElement, dbname, authzManager, &modifiedRolesObj); if (!status.isOK()) { return status; } updateSetBuilder.append("roles", modifiedRolesObj); } BSONObj updateSet = updateSetBuilder.obj(); if (updateSet.isEmpty()) { return Status(ErrorCodes::UserModificationFailed, "Must specify at least one field to update in updateUser"); } *parsedUpdateObj = BSON("$set" << updateSet); return Status::OK(); }