txmongo icon indicating copy to clipboard operation
txmongo copied to clipboard

txmongo.collection.Collection#rename() without admin DB

Open cpg1111 opened this issue 8 years ago • 3 comments

Hi there, I was trying to use txmongo.collection.Collection#rename() with a user without admin permissions. This can be done in Mongo just fine without admin permissions, as you can do db.collection.renameCollection() within a db you have rw permissions from in the mongo repl. Looking at the source for txmongo.collection.Collection#rename(), it does an admin command by default. Can this be switched to use the non-admin one by default and perhaps a flag for the admin version or a different method?

cpg1111 avatar Jan 31 '17 21:01 cpg1111

Hi,

I've just checked if txmongo's rename works for a user with single role "roles" : [ { "role" : "readWrite", "db" : "mydb" } ] and it does well.

According to the docs, renameCollection command should always be issued against admin database. Nevertheless it should work as long as you have readWrite role for a given DB (and if you are renaming collection inside this db, not moving it to another one).

If you look into the source code of REPL's renameCollection you can see that it issues the command against admin DB too:

> db.coll.renameCollection
function (newName, dropTarget) {
    if (arguments.length === 1 && typeof newName === 'object') {
        if (newName.hasOwnProperty('dropTarget')) {
            dropTarget = newName['dropTarget'];
        }
        newName = newName['to'];
    }
    if (typeof dropTarget === 'undefined') {
        dropTarget = false;
    }
    if (typeof newName !== 'string' || typeof dropTarget !== 'boolean') {
        throw Error(
            'renameCollection must either take a string and an optional boolean or an object.');
    }
    return this._db._adminCommand({
        renameCollection: this._fullName,
        to: this._db._name + "." + newName,
        dropTarget: dropTarget
    });
}
> db.adminCommand
function (obj, extra) {
        if (this._name == "admin")
            return this.runCommand(obj, extra);
        return this.getSiblingDB("admin").runCommand(obj, extra);
    }

Please check what roles does your DB user have and correct me if I'm wrong.

IlyaSkriblovsky avatar Feb 01 '17 05:02 IlyaSkriblovsky

So I am using a user with dbOwner permissions on a specific DB, but no role for the admin and I am geting a permissions issue. mongo has two renameCollection's the one you linked and this one. In the latter, it is exec'd on the selected DB, not requiring rw to admin.

cpg1111 avatar Feb 01 '17 15:02 cpg1111

Sorry, but I can't reproduce the issue.

I tried as follows:

  1. Started fresh clean MongoDB 3.4 instance (docker run --rm -it -p 27017:27017 mongo --auth)
  2. Ran mongo admin and did: db.createUser({user: 'userAdmin', pwd: 'qwe', roles:[{role: 'userAdminAnyDatabase', db: 'admin'}]})
  3. Ran mongo -u userAdmin -p qwe admin and did: db.createUser({user: 'test', pwd: 'test', roles:[{role: 'dbOwner', db: 'test'}]})
  4. Ran this python code:
from twisted.internet.task import react
from twisted.internet import defer
from txmongo.connection import ConnectionPool

@defer.inlineCallbacks
def main(reactor):
    conn = ConnectionPool('mongodb://test:test@localhost/test')
    yield conn.test.qwe.insert({'x': 42})
    yield conn.test.qwe.rename('rty')
    result = yield conn.test.rty.find()
    print result
    yield conn.disconnect()

react(main)

It printed [{u'x': 42}] as expected and rty collection remains in the database

mongo has two renameCollection's

They are actually the same: first one is the low-level DB command, second one is Mongo Shell's wrapper written in JavaScript. I've cited its source code above and you can see that it simply runs underlying renameCollection DB command.

Could you please try to reproduce the issue on a clean database and publish DB's user accounts setup and testing code?

IlyaSkriblovsky avatar Feb 01 '17 19:02 IlyaSkriblovsky