Skip to content

Commit ef7dc80

Browse files
committed
SERVER-9518 Handle otherDBRoles when initializing User object from V1 privilege documents
1 parent 4d51d8f commit ef7dc80

File tree

2 files changed

+101
-4
lines changed

2 files changed

+101
-4
lines changed

jstests/auth/otherDBRoles.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
var conn = MongoRunner.runMongod({auth : ""});
2+
3+
function assertGLENotOK(status) {
4+
assert(status.ok && status.err !== null,
5+
"Expected not-OK status object; found " + tojson(status));
6+
}
7+
8+
function assertGLEOK(status) {
9+
assert(status.ok && status.err === null,
10+
"Expected OK status object; found " + tojson(status));
11+
}
12+
13+
var adminDB = conn.getDB("admin");
14+
var testDB = conn.getDB("test");
15+
var test2DB = conn.getDB("test2");
16+
17+
// Can't use otherDBRoles outside of admin DB
18+
assert.throws(function() {
19+
testDB.addUser({user:'spencer',
20+
pwd:'x',
21+
roles:[],
22+
otherDBRoles: {test2: ['readWrite']}});
23+
});
24+
25+
testDB.addUser({user: 'spencer', pwd: 'x', roles: ['readWrite']});
26+
27+
adminDB.addUser({user:'spencer',
28+
userSource: 'test',
29+
roles:[],
30+
otherDBRoles: {test: ['dbAdmin'], test2: ['readWrite']}});
31+
32+
testDB.auth('spencer', 'x');
33+
34+
testDB.foo.insert({a:1});
35+
assertGLEOK(testDB.getLastErrorObj());
36+
assert.eq(1, testDB.foo.findOne().a);
37+
38+
// Make sure user got the dbAdmin role
39+
assert.commandWorked(testDB.foo.runCommand("compact"));
40+
41+
// Make sure the user got privileges on the test2 database.
42+
test2DB.foo.insert({a:1});
43+
assertGLEOK(test2DB.getLastErrorObj());
44+
assert.eq(1, test2DB.foo.findOne().a);
45+
46+
assert.commandFailed(test2DB.foo.runCommand("compact"));

src/mongo/db/auth/authorization_manager.cpp

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -777,12 +777,21 @@ namespace {
777777
}
778778
}
779779

780-
Status _initializeUserRolesFromV1PrivilegeDocument(
781-
User* user, const BSONObj& privDoc, const StringData& dbname) {
780+
Status _initializeUserRolesFromV1RolesArray(User* user,
781+
const BSONElement& rolesElement,
782+
const StringData& dbname) {
782783
static const char privilegesTypeMismatchMessage[] =
783-
"Roles in V1 user documents must be enumerated in an array of strings.";
784+
"Roles in V1 user documents must be enumerated in an array of strings.";
785+
786+
if (dbname == PrivilegeSet::WILDCARD_RESOURCE) {
787+
return Status(ErrorCodes::BadValue,
788+
PrivilegeSet::WILDCARD_RESOURCE + " is an invalid database name.");
789+
}
790+
791+
if (rolesElement.type() != Array)
792+
return Status(ErrorCodes::TypeMismatch, privilegesTypeMismatchMessage);
784793

785-
for (BSONObjIterator iter(privDoc["roles"].embeddedObject()); iter.more(); iter.next()) {
794+
for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) {
786795
BSONElement roleElement = *iter;
787796
if (roleElement.type() != String)
788797
return Status(ErrorCodes::TypeMismatch, privilegesTypeMismatchMessage);
@@ -792,6 +801,48 @@ namespace {
792801
return Status::OK();
793802
}
794803

804+
Status _initializeUserRolesFromV1PrivilegeDocument(
805+
User* user, const BSONObj& privDoc, const StringData& dbname) {
806+
Status status = _initializeUserRolesFromV1RolesArray(user,
807+
privDoc[ROLES_FIELD_NAME],
808+
dbname);
809+
if (!status.isOK()) {
810+
return status;
811+
}
812+
813+
// If "dbname" is the admin database, handle the otherDBPrivileges field, which
814+
// grants privileges on databases other than "dbname".
815+
BSONElement otherDbPrivileges = privDoc[OTHER_DB_ROLES_FIELD_NAME];
816+
if (dbname == ADMIN_DBNAME) {
817+
switch (otherDbPrivileges.type()) {
818+
case EOO:
819+
break;
820+
case Object: {
821+
for (BSONObjIterator iter(otherDbPrivileges.embeddedObject());
822+
iter.more(); iter.next()) {
823+
824+
BSONElement rolesElement = *iter;
825+
status = _initializeUserRolesFromV1RolesArray(user,
826+
rolesElement,
827+
rolesElement.fieldName());
828+
if (!status.isOK())
829+
return status;
830+
}
831+
break;
832+
}
833+
default:
834+
return Status(ErrorCodes::TypeMismatch,
835+
"Field \"otherDBRoles\" must be an object, if present.");
836+
}
837+
}
838+
else if (!otherDbPrivileges.eoo()) {
839+
return Status(ErrorCodes::BadValue, "Only the admin database may contain a field "
840+
"called \"otherDBRoles\"");
841+
}
842+
843+
return Status::OK();
844+
}
845+
795846
/**
796847
* Parses privDoc and initializes the user's "roles" field with the role list extracted
797848
* from the privilege document.

0 commit comments

Comments
 (0)