-
Type:
Bug
-
Resolution: Done
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
None
-
ALL
-
None
-
3
-
None
-
None
-
None
-
None
-
None
-
None
In our exceptional circumstances, we need to creat a user of role '_system' in the sharding cluster of 4.4.8/4.4.10/5.0. We find that the user can not list system tables by the 'show tables' command. However, the user of role '_system' can show system collections by 'show tables' in the config server.
As a user of the 'root' role, we can list system tables by the 'show tables' command both on the mongos and config server.
The `show tables` results of 'root' and '_system' are different on mongos. This seems abnormal, because both 'root' and '_system' should be superuser and can list system tables anywhere.
We think there is a BUG on the listCommands procedure of mongos.
We try to locate the BUG and find that there is a command rewrite procedure on the listCollections of mongos, which will add a filter to filter all system tables.
In the src/mongo/s/commands/commands_public.cpp of v4.4.8:
class CmdListCollections : public BasicCommand {class CmdListCollections : public BasicCommand {public: ...... BSONObj rewriteCommandForListingOwnCollections(OperationContext* opCtx, const std::string& dbName, const BSONObj& cmdObj) { // DB resource grants all non-system collections, so filter out system collections. // This is done inside the $or, since some system collections might be granted specific // privileges. if (authzSession->isAuthorizedForAnyActionOnResource( ResourcePattern::forDatabaseName(dbName))) { mutablebson::Element systemCollectionsFilter = rewrittenCmdObj.makeElementObject( "", BSON("name" << BSON("$regex" << BSONRegEx("^(?!system\\.)")))); uassertStatusOK(newFilterOr.pushBack(systemCollectionsFilter)); } // Compute the set of collection names which would be permissible to return. std::set<std::string> collectionNames; for (UserNameIterator nameIter = authzSession->getAuthenticatedUserNames(); nameIter.more(); nameIter.next()) { User* authUser = authzSession->lookupUser(*nameIter); const User::ResourcePrivilegeMap& resourcePrivilegeMap = authUser->getPrivileges(); for (const std::pair<ResourcePattern, Privilege>& resourcePrivilege : resourcePrivilegeMap) { const auto& resource = resourcePrivilege.first; if (resource.isCollectionPattern() || (resource.isExactNamespacePattern() && resource.databaseToMatch() == dbName)) { collectionNames.emplace(resource.collectionToMatch().toString()); } } } ...... } ......} cmdListCollections;