[SERVER-64549] User of role '__system' can not show system tables on mongos Created: 16/Mar/22  Updated: 10/Jun/22  Resolved: 04/Apr/22

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: 渣侨 渣 Assignee: Chris Kelly
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: PNG File image-2022-04-01-23-35-35-298.png    
Operating System: ALL
Participants:

 Description   

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;



 Comments   
Comment by Chris Kelly [ 04/Apr/22 ]

Hello zhangjiaqiao46@gmail.com,

 

I was able to reproduce the issue you indicated about not being able to run show tables on mongos from a user with the _system role on MongoDB 4.4.8. This role is generally reserved for user objects that represent cluster members, such as replica set members and mongos instances. You can read more about the __system role here.

You can use the userAdminAnyDatabase role to list collections on both mongos and the config server, or you can search for other built-in roles that may better fit your use case.

If you need further assistance, I'd like to encourage you to start by asking our community for help by posting on the MongoDB Developer Community Forums.

 

Regards,

Christopher

 

Comment by 渣侨 渣 [ 16/Mar/22 ]

Reproduce:

__system can not show system tables on mongos but can show system tables on config server.

use admin 
db.createUser({ user: 'test', pwd: '123', roles: [{role: '__system', db: 'admin'}] }) 
db.logout() 
db.auth('test', '123') 
show tables 

Comment by 渣侨 渣 [ 16/Mar/22 ]

In the src/mongo/s/commands/commands_public.cpp of v4.4.8:

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;

According to the filter definition, listCommands will filter all system tables except which the user has privileges of collection resource pattern to access. Users of __system role only have the privileges of forAnyResource pattern, so __system users can not list system tables by the 'show tables' command.

 

It seems that the command rewrite procedure of listCommands on the mongos needs to be improved.

Generated at Thu Feb 08 06:00:36 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.