Status checkAuthForCopydbCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { bool fromSelf = StringData(cmdObj.getStringField("fromhost")).empty(); StringData fromdb = cmdObj.getStringField("fromdb"); StringData todb = cmdObj.getStringField("todb"); // get system collections std::vector<std::string> legalClientSystemCollections; legalClientSystemCollections.push_back("system.js"); if (fromdb == "admin") { legalClientSystemCollections.push_back("system.users"); legalClientSystemCollections.push_back("system.roles"); legalClientSystemCollections.push_back("system.version"); } else if (fromdb == "local") { // TODO(spencer): shouldn't be possible. See SERVER-11383 legalClientSystemCollections.push_back("system.replset"); } // Check authorization on destination db ActionSet actions; actions.addAction(ActionType::insert); actions.addAction(ActionType::createIndex); if (shouldBypassDocumentValidationForCommand(cmdObj)) { actions.addAction(ActionType::bypassDocumentValidation); } if (!AuthorizationSession::get(client) ->isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(todb), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } actions.removeAllActions(); actions.addAction(ActionType::insert); for (size_t i = 0; i < legalClientSystemCollections.size(); ++i) { if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnNamespace( NamespaceString(todb, legalClientSystemCollections[i]), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } } if (fromSelf) { // If copying from self, also require privileges on source db actions.removeAllActions(); actions.addAction(ActionType::find); if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(fromdb), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } for (size_t i = 0; i < legalClientSystemCollections.size(); ++i) { if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnNamespace( NamespaceString(fromdb, legalClientSystemCollections[i]), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } } } return Status::OK(); }
Status checkAuthForRenameCollectionCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { NamespaceString sourceNS = NamespaceString(cmdObj.getStringField("renameCollection")); NamespaceString targetNS = NamespaceString(cmdObj.getStringField("to")); bool dropTarget = cmdObj["dropTarget"].trueValue(); if (sourceNS.db() == targetNS.db() && !sourceNS.isSystem() && !targetNS.isSystem()) { // If renaming within the same database, then if you have renameCollectionSameDB and // either can read both of source and dest collections or *can't* read either of source // or dest collection, then you get can do the rename, even without insert on the // destination collection. bool canRename = AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(sourceNS.db()), ActionType::renameCollectionSameDB); bool canDropTargetIfNeeded = true; if (dropTarget) { canDropTargetIfNeeded = AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(targetNS), ActionType::dropCollection); } bool canReadSrc = AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(sourceNS), ActionType::find); bool canReadDest = AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(targetNS), ActionType::find); if (canRename && canDropTargetIfNeeded && (canReadSrc || !canReadDest)) { return Status::OK(); } } // Check privileges on source collection ActionSet actions; actions.addAction(ActionType::find); actions.addAction(ActionType::dropCollection); if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(sourceNS), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } // Check privileges on dest collection actions.removeAllActions(); actions.addAction(ActionType::insert); actions.addAction(ActionType::createIndex); if (dropTarget) { actions.addAction(ActionType::dropCollection); } if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(targetNS), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } return Status::OK(); }
Status checkAuthForRenameCollectionCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { NamespaceString sourceNS = NamespaceString(cmdObj.getStringField("renameCollection")); NamespaceString targetNS = NamespaceString(cmdObj.getStringField("to")); bool dropTarget = cmdObj["dropTarget"].trueValue(); if (sourceNS.db() == targetNS.db() && !sourceNS.isSystem() && !targetNS.isSystem()) { bool authed1 = client->getAuthorizationSession()->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(sourceNS.db()), ActionType::renameCollectionSameDB); bool authed2 = true; if (dropTarget) { authed2 = client->getAuthorizationSession()->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(targetNS), ActionType::dropCollection); } if (authed1 && authed2) { return Status::OK(); } } // Check privileges on source collection ActionSet actions; actions.addAction(ActionType::find); actions.addAction(ActionType::dropCollection); if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(sourceNS), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } // Check privileges on dest collection actions.removeAllActions(); actions.addAction(ActionType::insert); actions.addAction(ActionType::createIndex); if (dropTarget) { actions.addAction(ActionType::dropCollection); } if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace(targetNS), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } return Status::OK(); }