Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

SERVER-7767 Support extended privilege document format in the Authori…

…zationManager.

Includes unit but not integration tests.
  • Loading branch information...
commit 50f22ef561c08c56b26e8f4e2bef5636180280f4 1 parent 385502f
@andy10gen andy10gen authored
View
4 src/mongo/db/auth/SConscript
@@ -16,7 +16,9 @@ env.StaticLibrary('authcore', ['action_set.cpp',
'principal_set.cpp',
'privilege.cpp',
'privilege_set.cpp'],
- LIBDEPS=['$BUILD_DIR/mongo/base/base', '$BUILD_DIR/mongo/stringutils'])
+ LIBDEPS=['$BUILD_DIR/mongo/base/base',
+ '$BUILD_DIR/mongo/bson',
+ '$BUILD_DIR/mongo/stringutils'])
env.StaticLibrary('authservercommon',
['auth_external_state_server_common.cpp'],
View
192 src/mongo/db/auth/authorization_manager.cpp
@@ -43,10 +43,29 @@ namespace mongo {
const std::string AuthorizationManager::SERVER_RESOURCE_NAME = "$SERVER";
const std::string AuthorizationManager::CLUSTER_RESOURCE_NAME = "$CLUSTER";
- namespace {
- const std::string ADMIN_DBNAME = "admin";
- const std::string LOCAL_DBNAME = "local";
- }
+namespace {
+ const std::string ADMIN_DBNAME = "admin";
+ const std::string LOCAL_DBNAME = "local";
+
+ const std::string ROLES_FIELD_NAME = "roles";
+ const std::string OTHER_DB_ROLES_FIELD_NAME = "otherDBRoles";
+ const std::string READONLY_FIELD_NAME = "readOnly";
+ const std::string USERNAME_FIELD_NAME = "user";
+ const std::string USERSOURCE_FIELD_NAME = "userSource";
+ const std::string PASSWORD_FIELD_NAME = "pwd";
+
+ const std::string SYSTEM_ROLE_READ = "read";
+ const std::string SYSTEM_ROLE_READ_WRITE = "readWrite";
+ const std::string SYSTEM_ROLE_USER_ADMIN = "userAdmin";
+ const std::string SYSTEM_ROLE_DB_ADMIN = "dbAdmin";
+ const std::string SYSTEM_ROLE_SERVER_ADMIN = "serverAdmin";
+ const std::string SYSTEM_ROLE_CLUSTER_ADMIN = "clusterAdmin";
+ const std::string SYSTEM_ROLE_READ_ANY_DB = "readAnyDB";
+ const std::string SYSTEM_ROLE_READ_WRITE_ANY_DB = "readWriteAnyDatabase";
+ const std::string SYSTEM_ROLE_USER_ADMIN_ANY_DB = "userAdminAnyDatabase";
+ const std::string SYSTEM_ROLE_DB_ADMIN_ANY_DB = "dbAdminAnyDatabase";
+
+} // namespace
// ActionSets for the various system roles. These ActionSets contain all the actions that
// a user of each system role is granted.
@@ -58,8 +77,10 @@ namespace mongo {
// compatibility with old-style read-only admin users.
ActionSet serverAdminRoleReadActions;
ActionSet serverAdminRoleWriteActions;
+ ActionSet serverAdminRoleActions;
ActionSet clusterAdminRoleReadActions;
ActionSet clusterAdminRoleWriteActions;
+ ActionSet clusterAdminRoleActions;
// Can only be performed by internal connections. Nothing ever explicitly grants these actions,
// but they're included when calling addAllActions on an ActionSet, which is how internal
// connections are granted their privileges.
@@ -142,6 +163,9 @@ namespace mongo {
serverAdminRoleWriteActions.addAction(ActionType::replSetReconfig);
serverAdminRoleWriteActions.addAction(ActionType::resync);
+ serverAdminRoleActions.addAllActionsFromSet(serverAdminRoleReadActions);
+ serverAdminRoleActions.addAllActionsFromSet(serverAdminRoleWriteActions);
+
// Cluster admin role
clusterAdminRoleReadActions.addAction(ActionType::getShardVersion);
clusterAdminRoleReadActions.addAction(ActionType::listShards);
@@ -162,6 +186,9 @@ namespace mongo {
clusterAdminRoleWriteActions.addAction(ActionType::split);
clusterAdminRoleWriteActions.addAction(ActionType::splitChunk);
+ clusterAdminRoleActions.addAllActionsFromSet(clusterAdminRoleReadActions);
+ clusterAdminRoleActions.addAllActionsFromSet(clusterAdminRoleWriteActions);
+
// Internal commands
internalActions.addAction(ActionType::clone);
internalActions.addAction(ActionType::handshake);
@@ -295,7 +322,7 @@ namespace mongo {
const PrincipalName& principal,
const BSONObj& privilegeDocument,
PrivilegeSet* result) {
- if (!privilegeDocument.hasField("privileges")) {
+ if (!privilegeDocument.hasField(ROLES_FIELD_NAME)) {
// Old-style (v2.2 and prior) privilege document
return _buildPrivilegeSetFromOldStylePrivilegeDocument(dbname,
principal,
@@ -303,10 +330,8 @@ namespace mongo {
result);
}
else {
- return Status(ErrorCodes::UnsupportedFormat,
- mongoutils::str::stream() << "Invalid privilege document received when "
- "trying to extract privileges: " << privilegeDocument,
- 0);
+ return _buildPrivilegeSetFromExtendedPrivilegeDocument(
+ dbname, principal, privilegeDocument, result);
}
}
@@ -315,25 +340,26 @@ namespace mongo {
const PrincipalName& principal,
const BSONObj& privilegeDocument,
PrivilegeSet* result) {
- if (!(privilegeDocument.hasField("user") && privilegeDocument.hasField("pwd"))) {
+ if (!(privilegeDocument.hasField(USERNAME_FIELD_NAME) &&
+ privilegeDocument.hasField(PASSWORD_FIELD_NAME))) {
+
return Status(ErrorCodes::UnsupportedFormat,
mongoutils::str::stream() << "Invalid old-style privilege document "
"received when trying to extract privileges: "
<< privilegeDocument,
0);
}
- if (privilegeDocument["user"].str() != principal.getUser()) {
+ if (privilegeDocument[USERNAME_FIELD_NAME].str() != principal.getUser()) {
return Status(ErrorCodes::BadValue,
mongoutils::str::stream() << "Principal name from privilege document \""
- << privilegeDocument["user"].str()
+ << privilegeDocument[USERNAME_FIELD_NAME].str()
<< "\" doesn't match name of provided Principal \""
<< principal.getUser()
<< "\"",
0);
}
- bool readOnly = privilegeDocument.hasField("readOnly") &&
- privilegeDocument["readOnly"].trueValue();
+ bool readOnly = privilegeDocument[READONLY_FIELD_NAME].trueValue();
ActionSet actions = getActionsForOldStyleUser(dbname, readOnly);
std::string resourceName = (dbname == ADMIN_DBNAME || dbname == LOCAL_DBNAME) ?
PrivilegeSet::WILDCARD_RESOURCE : dbname;
@@ -342,6 +368,144 @@ namespace mongo {
return Status::OK();
}
+ /**
+ * Adds to "outPrivileges" the privileges associated with having the named "role" on "dbname".
+ *
+ * Returns non-OK status if "role" is not a defined role in "dbname".
+ */
+ static Status _addPrivilegesForSystemRole(const std::string& dbname,
+ const std::string& role,
+ std::vector<Privilege>* outPrivileges) {
+ const bool isAdminDB = (dbname == ADMIN_DBNAME);
+
+ if (role == SYSTEM_ROLE_READ) {
+ outPrivileges->push_back(Privilege(dbname, readRoleActions));
+ }
+ else if (role == SYSTEM_ROLE_READ_WRITE) {
+ outPrivileges->push_back(Privilege(dbname, readWriteRoleActions));
+ }
+ else if (role == SYSTEM_ROLE_USER_ADMIN) {
+ outPrivileges->push_back(Privilege(dbname, userAdminRoleActions));
+ }
+ else if (role == SYSTEM_ROLE_DB_ADMIN) {
+ outPrivileges->push_back(Privilege(dbname, dbAdminRoleActions));
+ }
+ else if (isAdminDB && role == SYSTEM_ROLE_READ_ANY_DB) {
+ outPrivileges->push_back(Privilege(PrivilegeSet::WILDCARD_RESOURCE, readRoleActions));
+ }
+ else if (isAdminDB && role == SYSTEM_ROLE_READ_WRITE_ANY_DB) {
+ outPrivileges->push_back(
+ Privilege(PrivilegeSet::WILDCARD_RESOURCE, readWriteRoleActions));
+ }
+ else if (isAdminDB && role == SYSTEM_ROLE_USER_ADMIN_ANY_DB) {
+ outPrivileges->push_back(
+ Privilege(PrivilegeSet::WILDCARD_RESOURCE, userAdminRoleActions));
+ }
+ else if (isAdminDB && role == SYSTEM_ROLE_DB_ADMIN_ANY_DB) {
+ outPrivileges->push_back(
+ Privilege(PrivilegeSet::WILDCARD_RESOURCE, dbAdminRoleActions));
+ }
+ else if (isAdminDB && role == SYSTEM_ROLE_SERVER_ADMIN) {
+ outPrivileges->push_back(
+ Privilege(PrivilegeSet::WILDCARD_RESOURCE, serverAdminRoleActions));
+ }
+ else if (isAdminDB && role == SYSTEM_ROLE_CLUSTER_ADMIN) {
+ outPrivileges->push_back(
+ Privilege(PrivilegeSet::WILDCARD_RESOURCE, clusterAdminRoleActions));
+ }
+ else {
+ return Status(ErrorCodes::BadValue,
+ mongoutils::str::stream() <<"No such role, " << role <<
+ ", in database " << dbname);
+ }
+ return Status::OK();
+ }
+
+ /**
+ * Given a database name and a BSONElement representing an array of roles, populates
+ * "outPrivileges" with the privileges associated with the given roles on the named database.
+ *
+ * Returns Status::OK() on success.
+ */
+ static Status _getPrivilegesFromRoles(const std::string& dbname,
+ const BSONElement& rolesElement,
+ std::vector<Privilege>* outPrivileges) {
+
+ static const char privilegesTypeMismatchMessage[] =
+ "Roles must be enumerated in an array of strings.";
+
+ if (dbname == PrivilegeSet::WILDCARD_RESOURCE) {
+ return Status(ErrorCodes::BadValue,
+ PrivilegeSet::WILDCARD_RESOURCE + " is an invalid database name.");
+ }
+
+ if (rolesElement.type() != Array)
+ return Status(ErrorCodes::TypeMismatch, privilegesTypeMismatchMessage);
+
+ for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) {
+ BSONElement roleElement = *iter;
+ if (roleElement.type() != String)
+ return Status(ErrorCodes::TypeMismatch, privilegesTypeMismatchMessage);
+ Status status = _addPrivilegesForSystemRole(dbname, roleElement.str(), outPrivileges);
+ if (!status.isOK())
+ return status;
+ }
+ return Status::OK();
+ }
+
+ Status AuthorizationManager::_buildPrivilegeSetFromExtendedPrivilegeDocument(
+ const std::string& dbname,
+ const PrincipalName& principal,
+ const BSONObj& privilegeDocument,
+ PrivilegeSet* result) {
+
+ if (!privilegeDocument[READONLY_FIELD_NAME].eoo()) {
+ return Status(ErrorCodes::UnsupportedFormat,
+ "Privilege documents may not contain both \"readonly\" and "
+ "\"roles\" fields");
+ }
+
+ std::vector<Privilege> acquiredPrivileges;
+
+ // Acquire privileges on "dbname".
+ Status status = _getPrivilegesFromRoles(
+ dbname, privilegeDocument[ROLES_FIELD_NAME], &acquiredPrivileges);
+ if (!status.isOK())
+ return status;
+
+ // If "dbname" is the admin database, handle the otherDBPrivileges field, which
+ // grants privileges on databases other than "dbname".
+ BSONElement otherDbPrivileges = privilegeDocument[OTHER_DB_ROLES_FIELD_NAME];
+ if (dbname == ADMIN_DBNAME) {
+ switch (otherDbPrivileges.type()) {
+ case EOO:
+ break;
+ case Object: {
+ for (BSONObjIterator iter(otherDbPrivileges.embeddedObject());
+ iter.more(); iter.next()) {
+
+ BSONElement rolesElement = *iter;
+ status = _getPrivilegesFromRoles(
+ rolesElement.fieldName(), rolesElement, &acquiredPrivileges);
+ if (!status.isOK())
+ return status;
+ }
+ break;
+ }
+ default:
+ return Status(ErrorCodes::TypeMismatch,
+ "Field \"otherDBRoles\" must be an object, if present.");
+ }
+ }
+ else if (!otherDbPrivileges.eoo()) {
+ return Status(ErrorCodes::BadValue, "Only the admin database may contain a field "
+ "called \"otherDBRoles\"");
+ }
+
+ result->grantPrivileges(acquiredPrivileges, principal);
+ return Status::OK();
+ }
+
bool AuthorizationManager::checkAuthorization(const std::string& resource,
ActionType action) {
if (_externalState->shouldIgnoreAuthChecks())
View
11 src/mongo/db/auth/authorization_manager.h
@@ -158,6 +158,17 @@ namespace mongo {
const BSONObj& privilegeDocument,
PrivilegeSet* result);
+ // Parses extended-form (2.4+) privilege documents and returns a PrivilegeSet of all the
+ // privileges that the document grants.
+ //
+ // The document, "privilegeDocument", is assumed to describe privileges for "principal", and
+ // to come from database "dbname".
+ static Status _buildPrivilegeSetFromExtendedPrivilegeDocument(
+ const std::string& dbname,
+ const PrincipalName& principal,
+ const BSONObj& privilegeDocument,
+ PrivilegeSet* result);
+
scoped_ptr<AuthExternalState> _externalState;
// All the privileges that have been acquired by the authenticated principals.
View
267 src/mongo/db/auth/authorization_manager_test.cpp
@@ -17,10 +17,9 @@
* Unit tests of the AuthorizationManager type.
*/
-#include "mongo/db/auth/authorization_manager.h"
-
#include "mongo/base/status.h"
#include "mongo/db/auth/auth_external_state_mock.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/jsobj.h"
#include "mongo/unittest/unittest.h"
@@ -61,8 +60,8 @@ namespace {
ASSERT_FALSE(authManager.checkAuthorization("test", ActionType::insert));
}
- TEST(AuthorizationManagerTest, GetPrivilegesFromPrivilegeDocument) {
- PrincipalName principal("Spencer", "test");
+ TEST(AuthorizationManagerTest, GetPrivilegesFromPrivilegeDocumentCompatible) {
+ PrincipalName principal ("Spencer", "test");
BSONObj invalid;
BSONObj readWrite = BSON("user" << "Spencer" << "pwd" << "passwordHash");
BSONObj readOnly = BSON("user" << "Spencer" << "pwd" << "passwordHash" <<
@@ -112,5 +111,265 @@ namespace {
ASSERT(privilegeSet.hasPrivilege(Privilege("*", ActionType::insert)));
}
+ class PrivilegeDocumentParsing : public ::mongo::unittest::Test {
+ public:
+ PrivilegeDocumentParsing() : user("spencer", "test") {}
+
+ PrincipalName user;
+ PrivilegeSet privilegeSet;
+ };
+
+ TEST_F(PrivilegeDocumentParsing, VerifyRolesFieldMustBeAnArray) {
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << "read"),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, VerifyRejectionOfInvalidRoleNames) {
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("read" << "frim")),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantServerAdminRoleFromNonAdminDatabase) {
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("read" << "serverAdmin")),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::shutdown)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::dropDatabase)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantClusterAdminRoleFromNonAdminDatabase) {
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("read" << "clusterAdmin")),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::shutdown)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::dropDatabase)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantClusterReadFromNonAdminDatabase) {
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("read" << "readAnyDatabase")),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantClusterReadWriteFromNonAdminDatabase) {
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("read" << "readWriteAnyDatabase")),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::insert)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::insert)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantClusterUserAdminFromNonAdminDatabase) {
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("read" << "userAdminAnyDatabase")),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::userAdmin)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantClusterDBAdminFromNonAdminDatabase) {
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("read" << "dbAdminAnyDatabase")),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::clean)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::clean)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, VerifyOtherDBRolesMustBeAnObjectOfArraysOfStrings) {
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "admin",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("read") <<
+ "otherDBRoles" << BSON_ARRAY("read")),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::find)));
+
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "admin",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("read") <<
+ "otherDBRoles" << BSON("test2" << "read")),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::find)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantPrivilegesOnOtherDatabasesNormally) {
+ // Cannot grant privileges on other databases, except from admin database.
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("read") <<
+ "otherDBRoles" << BSON("test2" << BSON_ARRAY("read"))),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, SuccessfulSimpleReadGrant) {
+ // Grant read on test.
+ ASSERT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" << "roles" << BSON_ARRAY("read")),
+ &privilegeSet));
+
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::find)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, SuccessfulSimpleUserAdminTest) {
+ // Grant userAdmin on "test" database.
+ ASSERT_OK(AuthorizationManager::buildPrivilegeSet(
+ "test",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("userAdmin")),
+ &privilegeSet));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::userAdmin)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::userAdmin)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, GrantUserAdminOnAdmin) {
+ // Grant userAdmin on admin.
+ ASSERT_OK(AuthorizationManager::buildPrivilegeSet(
+ "admin",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("userAdmin")),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::userAdmin)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("admin", ActionType::userAdmin)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, GrantUserAdminOnTestViaAdmin) {
+ // Grant userAdmin on test via admin.
+ ASSERT_OK(AuthorizationManager::buildPrivilegeSet(
+ "admin",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSONArrayBuilder().arr() <<
+ "otherDBRoles" << BSON("test" << BSON_ARRAY("userAdmin"))),
+ &privilegeSet));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::userAdmin)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::userAdmin)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, SuccessfulClusterAdminTest) {
+ // Grant userAdminAnyDatabase.
+ ASSERT_OK(AuthorizationManager::buildPrivilegeSet(
+ "admin",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("userAdminAnyDatabase")),
+ &privilegeSet));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test2", ActionType::userAdmin)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("admin", ActionType::userAdmin)));
+ }
+
+
+ TEST_F(PrivilegeDocumentParsing, GrantClusterReadWrite) {
+ // Grant readWrite on everything via the admin database.
+ ASSERT_OK(AuthorizationManager::buildPrivilegeSet(
+ "admin",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("readWriteAnyDatabase")),
+ &privilegeSet));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test2", ActionType::find)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("admin", ActionType::find)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::insert)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test2", ActionType::insert)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("admin", ActionType::insert)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, ProhibitGrantOnWildcard) {
+ // Cannot grant readWrite to everythign using "otherDBRoles".
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "admin",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSONArrayBuilder().arr() <<
+ "otherDBRoles" << BSON("*" << BSON_ARRAY("readWrite"))),
+ &privilegeSet));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::find)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::insert)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::insert)));
+ ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::insert)));
+ }
+
+ TEST_F(PrivilegeDocumentParsing, GrantClusterAndServerAdmin) {
+ // Grant cluster and server admin
+ ASSERT_OK(AuthorizationManager::buildPrivilegeSet(
+ "admin",
+ user,
+ BSON("user" << "spencer" << "pwd" << "" <<
+ "roles" << BSON_ARRAY("clusterAdmin" << "serverAdmin")),
+ &privilegeSet));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::dropDatabase)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("test2", ActionType::dropDatabase)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("admin", ActionType::dropDatabase)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("$SERVER", ActionType::shutdown)));
+ ASSERT(privilegeSet.hasPrivilege(Privilege("$CLUSTER", ActionType::moveChunk)));
+ }
+
+ TEST(AuthorizationManagerTest, GetPrivilegesFromPrivilegeDocumentInvalid) {
+ BSONObj oldAndNewMixed = BSON("user" << "spencer" <<
+ "pwd" << "passwordHash" <<
+ "readOnly" << false <<
+ "roles" << BSON_ARRAY("write" << "userAdmin"));
+
+ PrincipalName principal("spencer", "anydb");
+ PrivilegeSet result;
+ ASSERT_NOT_OK(AuthorizationManager::buildPrivilegeSet(
+ "anydb", principal, oldAndNewMixed, &result));
+ }
+
} // namespace
} // namespace mongo
View
5 src/mongo/unittest/unittest.h
@@ -54,6 +54,11 @@
#define ASSERT_OK(EXPRESSION) ASSERT_EQUALS(Status::OK(), (EXPRESSION))
/**
+ * Assert that a status code is anything but OK.
+ */
+#define ASSERT_NOT_OK(EXPRESSION) ASSERT_NOT_EQUALS(Status::OK(), (EXPRESSION))
+
+/**
* Fails if "EXPRESSION" is true.
*/
#define ASSERT_FALSE(EXPRESSION) ::mongo::unittest::TestAssertion( __FILE__, __LINE__ ).failIf( \
Please sign in to comment.
Something went wrong with that request. Please try again.