summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSpencer Jackson <spencer.jackson@mongodb.com>2020-01-15 16:30:37 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-01-29 19:59:40 +0000
commita93cfd354467981c9cf944a4ada748d0226fdfb0 (patch)
treef7c2d82ba8e5dc19dec375b24d1264bf1e3d9018
parentc8868f90d0268db3bd597b334c3651979f458780 (diff)
downloadmongo-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.js8
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp39
-rw-r--r--src/mongo/db/auth/authorization_manager_test.cpp42
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 {