diff options
author | Spencer Jackson <spencer.jackson@mongodb.com> | 2020-01-15 16:30:37 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-01-29 19:59:40 +0000 |
commit | a93cfd354467981c9cf944a4ada748d0226fdfb0 (patch) | |
tree | f7c2d82ba8e5dc19dec375b24d1264bf1e3d9018 | |
parent | c8868f90d0268db3bd597b334c3651979f458780 (diff) | |
download | mongo-a93cfd354467981c9cf944a4ada748d0226fdfb0.tar.gz |
SERVER-45472 Ensure RoleGraph can serialize authentication restrictions to BSON
(cherry picked from commit 521e56b407ac72bc69a97a24d1253f51a5b6e81b)
(cherry picked from commit a10d0a22d5d009d27664967181042933ec1bef36)
(cherry picked from commit fb87cc88ecb5d300f14cda7bc238d7d5132118f5)
-rw-r--r-- | jstests/auth/authentication_restrictions_role.js | 8 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager.cpp | 39 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager_test.cpp | 42 |
3 files changed, 72 insertions, 17 deletions
diff --git a/jstests/auth/authentication_restrictions_role.js b/jstests/auth/authentication_restrictions_role.js index 759d874de3c..29b56aca933 100644 --- a/jstests/auth/authentication_restrictions_role.js +++ b/jstests/auth/authentication_restrictions_role.js @@ -57,6 +57,14 @@ assert.commandWorked(admin.runCommand({createRole: "role3", roles: [], privileges: []})); print("=== Role creation tests"); + print("When a role is updated, it retains authenticationRestrictions"); + assert.commandWorked(admin.runCommand({updateRole: "role2", roles: ["root"]})); + const role2Info = assert.commandWorked( + admin.runCommand({rolesInfo: "role2", showAuthenticationRestrictions: true})); + printjson(role2Info); + assert.eq(JSON.stringify([[{clientSource: ["127.0.0.1/32"]}]]), + JSON.stringify(role2Info.roles[0].authenticationRestrictions)); + print( "When a client creates roles with empty authenticationRestrictions, the operation succeeds, though it has no effect"); assert.commandWorked(admin.runCommand( diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp index dcd170c5f08..584f4fef33c 100644 --- a/src/mongo/db/auth/authorization_manager.cpp +++ b/src/mongo/db/auth/authorization_manager.cpp @@ -373,42 +373,55 @@ Status AuthorizationManager::getBSONForPrivileges(const PrivilegeVector& privile Status AuthorizationManager::getBSONForRole(RoleGraph* graph, const RoleName& roleName, - mutablebson::Element result) { + mutablebson::Element result) try { if (!graph->roleExists(roleName)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << roleName.getFullName() << "does not name an existing role"); } std::string id = mongoutils::str::stream() << roleName.getDB() << "." << roleName.getRole(); - result.appendString("_id", id).transitional_ignore(); - result.appendString(ROLE_NAME_FIELD_NAME, roleName.getRole()).transitional_ignore(); - result.appendString(ROLE_DB_FIELD_NAME, roleName.getDB()).transitional_ignore(); + uassertStatusOK(result.appendString("_id", id)); + uassertStatusOK( + result.appendString(AuthorizationManager::ROLE_NAME_FIELD_NAME, roleName.getRole())); + uassertStatusOK( + result.appendString(AuthorizationManager::ROLE_DB_FIELD_NAME, roleName.getDB())); // Build privileges array mutablebson::Element privilegesArrayElement = result.getDocument().makeElementArray("privileges"); - result.pushBack(privilegesArrayElement).transitional_ignore(); + uassertStatusOK(result.pushBack(privilegesArrayElement)); const PrivilegeVector& privileges = graph->getDirectPrivileges(roleName); - Status status = getBSONForPrivileges(privileges, privilegesArrayElement); - if (!status.isOK()) { - return status; - } + uassertStatusOK(getBSONForPrivileges(privileges, privilegesArrayElement)); // Build roles array mutablebson::Element rolesArrayElement = result.getDocument().makeElementArray("roles"); - result.pushBack(rolesArrayElement).transitional_ignore(); + uassertStatusOK(result.pushBack(rolesArrayElement)); for (RoleNameIterator roles = graph->getDirectSubordinates(roleName); roles.more(); roles.next()) { const RoleName& subRole = roles.get(); mutablebson::Element roleObj = result.getDocument().makeElementObject(""); - roleObj.appendString(ROLE_NAME_FIELD_NAME, subRole.getRole()).transitional_ignore(); - roleObj.appendString(ROLE_DB_FIELD_NAME, subRole.getDB()).transitional_ignore(); - rolesArrayElement.pushBack(roleObj).transitional_ignore(); + uassertStatusOK( + roleObj.appendString(AuthorizationManager::ROLE_NAME_FIELD_NAME, subRole.getRole())); + uassertStatusOK( + roleObj.appendString(AuthorizationManager::ROLE_DB_FIELD_NAME, subRole.getDB())); + uassertStatusOK(rolesArrayElement.pushBack(roleObj)); + } + + // Build authentication restrictions + auto restrictions = graph->getDirectAuthenticationRestrictions(roleName); + mutablebson::Element authenticationRestrictionsElement = + result.getDocument().makeElementArray("authenticationRestrictions"); + uassertStatusOK(result.pushBack(authenticationRestrictionsElement)); + if (restrictions) { + uassertStatusOK(authenticationRestrictionsElement.setValueArray(restrictions->toBSON())); } return Status::OK(); +} catch (...) { + return exceptionToStatus(); } + Status AuthorizationManager::_initializeUserFromPrivilegeDocument(User* user, const BSONObj& privDoc) { V2UserDocumentParser parser; diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp index 2b8472a7f77..4b3e796a006 100644 --- a/src/mongo/db/auth/authorization_manager_test.cpp +++ b/src/mongo/db/auth/authorization_manager_test.cpp @@ -38,6 +38,7 @@ #include "mongo/config.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/address_restriction.h" #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/authz_manager_external_state_mock.h" @@ -77,16 +78,21 @@ TEST(RoleParsingTest, BuildRoleBSON) { RoleName roleA("roleA", "dbA"); RoleName roleB("roleB", "dbB"); RoleName roleC("roleC", "dbC"); + RoleName roleD("roleD", "dbD"); ActionSet actions; actions.addAction(ActionType::find); actions.addAction(ActionType::insert); + SharedRestrictionDocument restrictions = uassertStatusOK(parseAuthenticationRestriction( + BSON_ARRAY(BSON("clientSource" << BSON_ARRAY("127.0.0.1"))))); ASSERT_OK(graph.createRole(roleA)); ASSERT_OK(graph.createRole(roleB)); ASSERT_OK(graph.createRole(roleC)); + ASSERT_OK(graph.createRole(roleD)); ASSERT_OK(graph.addRoleToRole(roleA, roleC)); ASSERT_OK(graph.addRoleToRole(roleA, roleB)); + ASSERT_OK(graph.addRoleToRole(roleA, roleD)); ASSERT_OK(graph.addRoleToRole(roleB, roleC)); ASSERT_OK(graph.addPrivilegeToRole( @@ -95,6 +101,7 @@ TEST(RoleParsingTest, BuildRoleBSON) { roleB, Privilege(ResourcePattern::forExactNamespace(NamespaceString("dbB.foo")), actions))); ASSERT_OK( graph.addPrivilegeToRole(roleC, Privilege(ResourcePattern::forClusterResource(), actions))); + ASSERT_OK(graph.replaceRestrictionsForRole(roleD, restrictions)); ASSERT_OK(graph.recomputePrivilegeData()); @@ -107,18 +114,20 @@ TEST(RoleParsingTest, BuildRoleBSON) { ASSERT_EQUALS("roleA", roleDoc["role"].String()); ASSERT_EQUALS("dbA", roleDoc["db"].String()); - vector<BSONElement> privs = roleDoc["privileges"].Array(); + ASSERT_TRUE(roleDoc["authenticationRestrictions"].Array().empty()); + + std::vector<BSONElement> privs = roleDoc["privileges"].Array(); ASSERT_EQUALS(1U, privs.size()); ASSERT_EQUALS("", privs[0].Obj()["resource"].Obj()["db"].String()); ASSERT_EQUALS("", privs[0].Obj()["resource"].Obj()["collection"].String()); ASSERT(privs[0].Obj()["resource"].Obj()["cluster"].eoo()); - vector<BSONElement> actionElements = privs[0].Obj()["actions"].Array(); + std::vector<BSONElement> actionElements = privs[0].Obj()["actions"].Array(); ASSERT_EQUALS(2U, actionElements.size()); ASSERT_EQUALS("find", actionElements[0].String()); ASSERT_EQUALS("insert", actionElements[1].String()); - vector<BSONElement> roles = roleDoc["roles"].Array(); - ASSERT_EQUALS(2U, roles.size()); + std::vector<BSONElement> roles = roleDoc["roles"].Array(); + ASSERT_EQUALS(3U, roles.size()); ASSERT_EQUALS("roleC", roles[0].Obj()["role"].String()); ASSERT_EQUALS("dbC", roles[0].Obj()["db"].String()); ASSERT_EQUALS("roleB", roles[1].Obj()["role"].String()); @@ -133,6 +142,8 @@ TEST(RoleParsingTest, BuildRoleBSON) { ASSERT_EQUALS("roleB", roleDoc["role"].String()); ASSERT_EQUALS("dbB", roleDoc["db"].String()); + ASSERT_TRUE(roleDoc["authenticationRestrictions"].Array().empty()); + privs = roleDoc["privileges"].Array(); ASSERT_EQUALS(1U, privs.size()); ASSERT_EQUALS("dbB", privs[0].Obj()["resource"].Obj()["db"].String()); @@ -157,6 +168,8 @@ TEST(RoleParsingTest, BuildRoleBSON) { ASSERT_EQUALS("roleC", roleDoc["role"].String()); ASSERT_EQUALS("dbC", roleDoc["db"].String()); + ASSERT_TRUE(roleDoc["authenticationRestrictions"].Array().empty()); + privs = roleDoc["privileges"].Array(); ASSERT_EQUALS(1U, privs.size()); ASSERT(privs[0].Obj()["resource"].Obj()["cluster"].Bool()); @@ -169,6 +182,27 @@ TEST(RoleParsingTest, BuildRoleBSON) { roles = roleDoc["roles"].Array(); ASSERT_EQUALS(0U, roles.size()); + + // Role D + doc.reset(); + ASSERT_OK(AuthorizationManager::getBSONForRole(&graph, roleD, doc.root())); + roleDoc = doc.getObject(); + + ASSERT_EQUALS("dbD.roleD", roleDoc["_id"].String()); + ASSERT_EQUALS("roleD", roleDoc["role"].String()); + ASSERT_EQUALS("dbD", roleDoc["db"].String()); + + ASSERT_FALSE(roleDoc["authenticationRestrictions"].Array().empty()); + auto restrictionObj = BSONArray(roleDoc["authenticationRestrictions"].Obj()); + SharedRestrictionDocument parsedRestrictions = + uassertStatusOK(parseAuthenticationRestriction(restrictionObj)); + ASSERT_EQ(restrictions->toString(), parsedRestrictions->toString()); + + privs = roleDoc["privileges"].Array(); + ASSERT_TRUE(privs.empty()); + + roles = roleDoc["roles"].Array(); + ASSERT_EQUALS(0U, roles.size()); } class AuthorizationManagerTest : public ::mongo::unittest::Test { |