Status checkAuthForRolesInfoCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); auth::RolesInfoArgs args; Status status = auth::parseRolesInfoCommand(cmdObj, dbname, &args); if (!status.isOK()) { return status; } if (args.allForDB) { if (!authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(dbname), ActionType::viewRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to view roles from the " << dbname << " database"); } } else { for (size_t i = 0; i < args.roleNames.size(); ++i) { if (authzSession->isAuthenticatedAsUserWithRole(args.roleNames[i])) { continue; // Can always see roles that you are a member of } if (!authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(args.roleNames[i].getDB()), ActionType::viewRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to view roles from the " << args.roleNames[i].getDB() << " database"); } } } return Status::OK(); }
Status checkAuthForUsersInfoCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); auth::UsersInfoArgs args; Status status = auth::parseUsersInfoCommand(cmdObj, dbname, &args); if (!status.isOK()) { return status; } if (args.allForDB) { if (!authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(dbname), ActionType::viewUser)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to view users from the " << dbname << " database"); } } else { for (size_t i = 0; i < args.userNames.size(); ++i) { if (authzSession->lookupUser(args.userNames[i])) { continue; // Can always view users you are logged in as } if (!authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(args.userNames[i].getDB()), ActionType::viewUser)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to view users from the " << dbname << " database"); } } } return Status::OK(); }
Status checkAuthForUpdateUserCommand(Client* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); auth::CreateOrUpdateUserArgs args; Status status = auth::parseCreateOrUpdateUserCommands(cmdObj, "updateUser", dbname, &args); if (!status.isOK()) { return status; } if (args.hasPassword) { if (!authzSession->isAuthorizedToChangeOwnPasswordAsUser(args.userName) && !authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(args.userName.getDB()), ActionType::changePassword)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to change password of user: "******"Not authorized to change customData of user: "******"In order to use updateUser to set roles array, must be " "authorized to revoke any role in the system"); } status = checkAuthorizedToGrantRoles(authzSession, args.roles); if (!status.isOK()) { return status; } } status = checkAuthorizedToSetRestrictions( authzSession, static_cast<bool>(args.authenticationRestrictions), args.userName.getDB()); if (!status.isOK()) { return status; } return Status::OK(); }
Status checkAuthForCreateUserCommand(Client* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); auth::CreateOrUpdateUserArgs args; Status status = auth::parseCreateOrUpdateUserCommands(cmdObj, "createUser", dbname, &args); if (!status.isOK()) { return status; } if (!authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(args.userName.getDB()), ActionType::createUser)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to create users on db: " << args.userName.getDB()); } status = checkAuthorizedToGrantRoles(authzSession, args.roles); if (!status.isOK()) { return status; } status = checkAuthorizedToSetRestrictions( authzSession, static_cast<bool>(args.authenticationRestrictions), args.userName.getDB()); if (!status.isOK()) { return status; } return Status::OK(); }
Status checkAuthForUpdateRoleCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); auth::CreateOrUpdateRoleArgs args; Status status = auth::parseCreateOrUpdateRoleCommands(cmdObj, "updateRole", dbname, &args); if (!status.isOK()) { return status; } // You don't know what roles or privileges you might be revoking, so require the ability // to revoke any role (or privilege) in the system. if (!authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forAnyNormalResource(), ActionType::revokeRole)) { return Status(ErrorCodes::Unauthorized, "updateRole command required the ability to revoke any role in the " "system"); } status = checkAuthorizedToGrantRoles(authzSession, args.roles); if (!status.isOK()) { return status; } return checkAuthorizedToGrantPrivileges(authzSession, args.privileges); }
Status checkAuthForAuthSchemaUpgradeCommand(ClientBasic* client) { AuthorizationSession* authzSession = AuthorizationSession::get(client); if (!authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), ActionType::authSchemaUpgrade)) { return Status(ErrorCodes::Unauthorized, "Not authorized to run authSchemaUpgrade command."); } return Status::OK(); }
Status checkAuthForInvalidateUserCacheCommand(Client* client) { AuthorizationSession* authzSession = AuthorizationSession::get(client); if (!authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), ActionType::invalidateUserCache)) { return Status(ErrorCodes::Unauthorized, "Not authorized to invalidate user cache"); } return Status::OK(); }
Status checkAuthForGetUserCacheGenerationCommand(Client* client) { AuthorizationSession* authzSession = AuthorizationSession::get(client); if (!authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), ActionType::internal)) { return Status(ErrorCodes::Unauthorized, "Not authorized to get cache generation"); } return Status::OK(); }
virtual Status checkAuthForCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); // Check for the listCollections ActionType on the database // or find on system.namespaces for pre 3.0 systems. if (authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(dbname), ActionType::listCollections) || authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(NamespaceString(dbname, "system.namespaces")), ActionType::find)) { return Status::OK(); } return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to create users on db: " << dbname); }
Status checkAuthForCommand(Client* client, const std::string& dbname, const BSONObj& cmdObj) final { AuthorizationSession* authzSession = AuthorizationSession::get(client); if (authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), ActionType::replSetResizeOplog)) { return Status::OK(); } return Status(ErrorCodes::Unauthorized, "Unauthorized"); }
Status checkAuthForDropAllRolesFromDatabaseCommand(Client* client, const std::string& dbname) { AuthorizationSession* authzSession = AuthorizationSession::get(client); if (!authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(dbname), ActionType::dropRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to drop roles from the " << dbname << " database"); } return Status::OK(); }
Status checkAuthForCommand(Client* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); ResourcePattern pattern = parseResourcePattern(dbname, cmdObj); if (authzSession->isAuthorizedForActionsOnResource(pattern, _actionType)) { return Status::OK(); } return Status(ErrorCodes::Unauthorized, "unauthorized"); }
Status IndexFilterCommand::checkAuthForCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); ResourcePattern pattern = parseResourcePattern(dbname, cmdObj); if (authzSession->isAuthorizedForActionsOnResource(pattern, ActionType::planCacheIndexFilter)) { return Status::OK(); } return Status(ErrorCodes::Unauthorized, "unauthorized"); }
Status checkAuthForCommand(Client* client, const std::string& dbname, const BSONObj& cmdObj) const override { AuthorizationSession* authzSession = AuthorizationSession::get(client); // Check for the listIndexes ActionType on the database, or find on system.indexes for pre // 3.0 systems. const NamespaceString ns(parseNs(dbname, cmdObj)); if (authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), ActionType::listIndexes) || authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(NamespaceString(dbname, "system.indexes")), ActionType::find)) { return Status::OK(); } return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to list indexes on collection: " << ns.coll()); }
Status checkAuthForMergeAuthzCollectionsCommand(Client* client, const BSONObj& cmdObj) { auth::MergeAuthzCollectionsArgs args; Status status = auth::parseMergeAuthzCollectionsCommand(cmdObj, &args); if (!status.isOK()) { return status; } AuthorizationSession* authzSession = AuthorizationSession::get(client); ActionSet actions; actions.addAction(ActionType::createUser); actions.addAction(ActionType::createRole); actions.addAction(ActionType::grantRole); actions.addAction(ActionType::revokeRole); if (args.drop) { actions.addAction(ActionType::dropUser); actions.addAction(ActionType::dropRole); } if (!authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forAnyNormalResource(), actions)) { return Status(ErrorCodes::Unauthorized, "Not authorized to update user/role data using _mergeAuthzCollections" " command"); } if (!args.usersCollName.empty() && !authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(NamespaceString(args.usersCollName)), ActionType::find)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to read " << args.usersCollName); } if (!args.rolesCollName.empty() && !authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(NamespaceString(args.rolesCollName)), ActionType::find)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to read " << args.rolesCollName); } return Status::OK(); }
Status ProfileCmdBase::checkAuthForCommand(Client* client, const std::string& dbName, const BSONObj& cmdObj) const { AuthorizationSession* authzSession = AuthorizationSession::get(client); auto request = ProfileCmdRequest::parse(IDLParserErrorContext("profile"), cmdObj); const auto profilingLevel = request.getCommandParameter(); if (profilingLevel < 0 && !request.getSlowms() && !request.getSampleRate()) { // If the user just wants to view the current values of 'slowms' and 'sampleRate', they // only need read rights on system.profile, even if they can't change the profiling level. if (authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace({dbName, "system.profile"}), ActionType::find)) { return Status::OK(); } } return authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(dbName), ActionType::enableProfiler) ? Status::OK() : Status(ErrorCodes::Unauthorized, "unauthorized"); }
Status checkAuthForApplyOpsCommand(OperationContext* txn, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authSession = AuthorizationSession::get(txn->getClient()); ApplyOpsValidity validity = validateApplyOpsCommand(cmdObj); if (validity == ApplyOpsValidity::kNeedsSuperuser) { std::vector<Privilege> universalPrivileges; RoleGraph::generateUniversalPrivileges(&universalPrivileges); if (!authSession->isAuthorizedForPrivileges(universalPrivileges)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } return Status::OK(); } fassert(40314, validity == ApplyOpsValidity::kOk); boost::optional<DisableDocumentValidation> maybeDisableValidation; if (shouldBypassDocumentValidationForCommand(cmdObj)) maybeDisableValidation.emplace(txn); const bool alwaysUpsert = cmdObj.hasField("alwaysUpsert") ? cmdObj["alwaysUpsert"].trueValue() : true; checkBSONType(BSONType::Array, cmdObj.firstElement()); for (const BSONElement& e : cmdObj.firstElement().Array()) { checkBSONType(BSONType::Object, e); Status status = checkOperationAuthorization(txn, dbname, e.Obj(), alwaysUpsert); if (!status.isOK()) { return status; } } BSONElement preconditions = cmdObj["preCondition"]; if (!preconditions.eoo()) { for (const BSONElement& precondition : preconditions.Array()) { checkBSONType(BSONType::Object, precondition); BSONElement nsElem = precondition.Obj()["ns"]; checkBSONType(BSONType::String, nsElem); NamespaceString nss(nsElem.checkAndGetStringData()); if (!authSession->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(nss), ActionType::find)) { return Status(ErrorCodes::Unauthorized, "Unauthorized to check precondition"); } } } return Status::OK(); }
Status checkAuthForCommand(Client* client, const std::string& dbName, const BSONObj& cmdObj) const final { AuthorizationSession* authzSession = AuthorizationSession::get(client); if (authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), ActionType::inprog)) { return Status::OK(); } if (authzSession->isAuthenticated() && cmdObj["$ownOps"].trueValue()) { return Status::OK(); } return Status(ErrorCodes::Unauthorized, "Unauthorized"); }
Status checkAuthForDropRoleCommand(Client* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); RoleName roleName; Status status = auth::parseDropRoleCommand(cmdObj, dbname, &roleName); if (!status.isOK()) { return status; } if (!authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(roleName.getDB()), ActionType::dropRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to drop roles from the " << roleName.getDB() << " database"); } return Status::OK(); }
Status checkAuthForDropUserCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); UserName userName; BSONObj unusedWriteConcern; Status status = auth::parseAndValidateDropUserCommand(cmdObj, dbname, &userName, &unusedWriteConcern); if (!status.isOK()) { return status; } if (!authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(userName.getDB()), ActionType::dropUser)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to drop users from the " << userName.getDB() << " database"); } return Status::OK(); }
static StatusWith<std::tuple<stdx::unique_lock<Client>, OperationContext*>> _findOp( ClientBasic* client, unsigned int opId) { AuthorizationSession* authzSession = AuthorizationSession::get(client); for (ServiceContext::LockedClientsCursor cursor(client->getServiceContext()); Client* opClient = cursor.next();) { stdx::unique_lock<Client> lk(*opClient); OperationContext* opCtx = opClient->getOperationContext(); if (opCtx && opCtx->getOpID() == opId) { if (authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forClusterResource(), ActionType::killop) || authzSession->isCoauthorizedWithClient(opClient)) { return {std::make_tuple(std::move(lk), opCtx)}; } break; } } return Status(ErrorCodes::NoSuchKey, str::stream() << "Could not access opID: " << opId); }
Status checkAuthForCreateRoleCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); auth::CreateOrUpdateRoleArgs args; Status status = auth::parseCreateOrUpdateRoleCommands(cmdObj, "createRole", dbname, &args); if (!status.isOK()) { return status; } if (!authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(args.roleName.getDB()), ActionType::createRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to create roles on db: " << args.roleName.getDB()); } status = checkAuthorizedToGrantRoles(authzSession, args.roles); if (!status.isOK()) { return status; } return checkAuthorizedToGrantPrivileges(authzSession, args.privileges); }
Status checkAuthForCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) final { AuthorizationSession* authzSession = AuthorizationSession::get(client); if (authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), ActionType::killop)) { // If we have administrative permission to run killop, we don't need to traverse the // Client list to figure out if we own the operation which will be terminated. return Status::OK(); } bool isAuthenticated = AuthorizationSession::get(client)->getAuthenticatedUserNames().more(); if (isAuthenticated) { long long opId = parseOpId(cmdObj); auto swLkAndOp = _findOp(client, opId); if (swLkAndOp.isOK()) { // We were able to find the Operation, and we were authorized to interact with it. return Status::OK(); } } return Status(ErrorCodes::Unauthorized, "Unauthorized"); }
bool handleSpecialNamespaces( Request& r , QueryMessage& q ) { const char * ns = strstr( r.getns() , ".$cmd.sys." ); if ( ! ns ) return false; ns += 10; BSONObjBuilder b; vector<Shard> shards; ClientBasic* client = ClientBasic::getCurrent(); AuthorizationSession* authSession = client->getAuthorizationSession(); if ( strcmp( ns , "inprog" ) == 0 ) { const bool isAuthorized = authSession->isAuthorizedForActionsOnResource( ResourcePattern::forClusterResource(), ActionType::inprog); audit::logInProgAuthzCheck( client, q.query, isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized); uassert(ErrorCodes::Unauthorized, "not authorized to run inprog", isAuthorized); Shard::getAllShards( shards ); BSONArrayBuilder arr( b.subarrayStart( "inprog" ) ); for ( unsigned i=0; i<shards.size(); i++ ) { Shard shard = shards[i]; ScopedDbConnection conn(shard.getConnString()); BSONObj temp = conn->findOne( r.getns() , q.query ); if ( temp["inprog"].isABSONObj() ) { BSONObjIterator i( temp["inprog"].Obj() ); while ( i.more() ) { BSONObjBuilder x; BSONObjIterator j( i.next().Obj() ); while( j.more() ) { BSONElement e = j.next(); if ( str::equals( e.fieldName() , "opid" ) ) { stringstream ss; ss << shard.getName() << ':' << e.numberInt(); x.append( "opid" , ss.str() ); } else if ( str::equals( e.fieldName() , "client" ) ) { x.appendAs( e , "client_s" ); } else { x.append( e ); } } arr.append( x.obj() ); } } conn.done(); } arr.done(); } else if ( strcmp( ns , "killop" ) == 0 ) { const bool isAuthorized = authSession->isAuthorizedForActionsOnResource( ResourcePattern::forClusterResource(), ActionType::killop); audit::logKillOpAuthzCheck( client, q.query, isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized); uassert(ErrorCodes::Unauthorized, "not authorized to run killop", isAuthorized); BSONElement e = q.query["op"]; if ( e.type() != String ) { b.append( "err" , "bad op" ); b.append( e ); } else { b.append( e ); string s = e.String(); string::size_type i = s.find( ':' ); if ( i == string::npos ) { b.append( "err" , "bad opid" ); } else { string shard = s.substr( 0 , i ); int opid = atoi( s.substr( i + 1 ).c_str() ); b.append( "shard" , shard ); b.append( "shardid" , opid ); log() << "want to kill op: " << e << endl; Shard s(shard); ScopedDbConnection conn(s.getConnString()); conn->findOne( r.getns() , BSON( "op" << opid ) ); conn.done(); } } } else if ( strcmp( ns , "unlock" ) == 0 ) { b.append( "err" , "can't do unlock through mongos" ); } else { warning() << "unknown sys command [" << ns << "]" << endl; return false; } BSONObj x = b.done(); replyToQuery(0, r.p(), r.m(), x); return true; }