summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/auth/authorization_manager.h5
-rw-r--r--src/mongo/db/auth/authorization_manager_impl.cpp5
-rw-r--r--src/mongo/db/auth/authorization_manager_impl.h2
-rw-r--r--src/mongo/db/auth/authz_manager_external_state.cpp17
-rw-r--r--src/mongo/db/auth/authz_manager_external_state.h10
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_d.cpp7
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_d.h23
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.cpp19
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.h8
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_mock.cpp8
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_mock.h25
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.cpp51
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.h17
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp25
-rw-r--r--src/mongo/embedded/embedded_auth_manager.cpp4
15 files changed, 180 insertions, 46 deletions
diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h
index 27fc4c57bb3..01790c106db 100644
--- a/src/mongo/db/auth/authorization_manager.h
+++ b/src/mongo/db/auth/authorization_manager.h
@@ -214,6 +214,11 @@ public:
/**
* Delegates method call to the underlying AuthzManagerExternalState.
*/
+ virtual Status rolesExist(OperationContext* opCtx, const std::vector<RoleName>& roleNames) = 0;
+
+ /**
+ * Delegates method call to the underlying AuthzManagerExternalState.
+ */
virtual Status getRoleDescription(OperationContext* opCtx,
const RoleName& roleName,
PrivilegeFormat privilegeFormat,
diff --git a/src/mongo/db/auth/authorization_manager_impl.cpp b/src/mongo/db/auth/authorization_manager_impl.cpp
index a2ba1112eec..42439d4e791 100644
--- a/src/mongo/db/auth/authorization_manager_impl.cpp
+++ b/src/mongo/db/auth/authorization_manager_impl.cpp
@@ -416,6 +416,11 @@ Status AuthorizationManagerImpl::getUserDescription(OperationContext* opCtx,
return _externalState->getUserDescription(opCtx, UserRequest(userName, boost::none), result);
}
+Status AuthorizationManagerImpl::rolesExist(OperationContext* opCtx,
+ const std::vector<RoleName>& roleNames) {
+ return _externalState->rolesExist(opCtx, roleNames);
+}
+
Status AuthorizationManagerImpl::getRoleDescription(OperationContext* opCtx,
const RoleName& roleName,
PrivilegeFormat privileges,
diff --git a/src/mongo/db/auth/authorization_manager_impl.h b/src/mongo/db/auth/authorization_manager_impl.h
index ba2d214d12a..933bbc02e32 100644
--- a/src/mongo/db/auth/authorization_manager_impl.h
+++ b/src/mongo/db/auth/authorization_manager_impl.h
@@ -72,6 +72,8 @@ public:
const UserName& userName,
BSONObj* result) override;
+ Status rolesExist(OperationContext* opCtx, const std::vector<RoleName>& roleNames) override;
+
Status getRoleDescription(OperationContext* opCtx,
const RoleName& roleName,
PrivilegeFormat privilegeFormat,
diff --git a/src/mongo/db/auth/authz_manager_external_state.cpp b/src/mongo/db/auth/authz_manager_external_state.cpp
index 8384fa2b924..5d2eb103f95 100644
--- a/src/mongo/db/auth/authz_manager_external_state.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state.cpp
@@ -46,4 +46,21 @@ std::unique_ptr<AuthzManagerExternalState> AuthzManagerExternalState::create() {
AuthzManagerExternalState::AuthzManagerExternalState() = default;
AuthzManagerExternalState::~AuthzManagerExternalState() = default;
+Status AuthzManagerExternalState::makeRoleNotFoundStatus(
+ const stdx::unordered_set<RoleName>& unknownRoles) {
+ dassert(unknownRoles.size());
+
+ char delim = ':';
+ StringBuilder sb;
+ sb << "Could not find role";
+ if (unknownRoles.size() > 1) {
+ sb << 's';
+ }
+ for (const auto& unknownRole : unknownRoles) {
+ sb << delim << ' ' << unknownRole.toString();
+ delim = ',';
+ }
+ return {ErrorCodes::RoleNotFound, sb.str()};
+}
+
} // namespace mongo
diff --git a/src/mongo/db/auth/authz_manager_external_state.h b/src/mongo/db/auth/authz_manager_external_state.h
index 7dde1480d96..867ea493a5f 100644
--- a/src/mongo/db/auth/authz_manager_external_state.h
+++ b/src/mongo/db/auth/authz_manager_external_state.h
@@ -100,6 +100,11 @@ public:
BSONObj* result) = 0;
/**
+ * Checks to see if the named roles exist.
+ */
+ virtual Status rolesExist(OperationContext* opCtx, const std::vector<RoleName>& roleNames) = 0;
+
+ /**
* Writes into "result" a document describing the named role and returns Status::OK(). If
* showPrivileges is kOmit or kShowPrivileges, the description includes the roles which the
* named role is a member of, including those memberships held implicitly through other roles
@@ -173,6 +178,11 @@ public:
protected:
AuthzManagerExternalState(); // This class should never be instantiated directly.
+
+ /**
+ * Construct a Status about one or more unknown roles.
+ */
+ static Status makeRoleNotFoundStatus(const stdx::unordered_set<RoleName>&);
};
} // namespace mongo
diff --git a/src/mongo/db/auth/authz_manager_external_state_d.cpp b/src/mongo/db/auth/authz_manager_external_state_d.cpp
index 2d143fee899..a5b66fe2622 100644
--- a/src/mongo/db/auth/authz_manager_external_state_d.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_d.cpp
@@ -88,6 +88,13 @@ Status AuthzManagerExternalStateMongod::findOne(OperationContext* opCtx,
<< query);
}
+bool AuthzManagerExternalStateMongod::hasOne(OperationContext* opCtx,
+ const NamespaceString& collectionName,
+ const BSONObj& query) {
+ AutoGetCollectionForReadCommand ctx(opCtx, collectionName);
+ return !Helpers::findOne(opCtx, ctx.getCollection(), query, false).isNull();
+}
+
namespace {
std::unique_ptr<AuthzManagerExternalState> authzManagerExternalStateCreateImpl() {
diff --git a/src/mongo/db/auth/authz_manager_external_state_d.h b/src/mongo/db/auth/authz_manager_external_state_d.h
index 289a7567236..dfb636adba0 100644
--- a/src/mongo/db/auth/authz_manager_external_state_d.h
+++ b/src/mongo/db/auth/authz_manager_external_state_d.h
@@ -51,17 +51,20 @@ public:
virtual ~AuthzManagerExternalStateMongod();
std::unique_ptr<AuthzSessionExternalState> makeAuthzSessionExternalState(
- AuthorizationManager* authzManager) override;
+ AuthorizationManager* authzManager) final;
- virtual Status findOne(OperationContext* opCtx,
- const NamespaceString& collectionName,
- const BSONObj& query,
- BSONObj* result);
- virtual Status query(OperationContext* opCtx,
- const NamespaceString& collectionName,
- const BSONObj& query,
- const BSONObj& projection,
- const std::function<void(const BSONObj&)>& resultProcessor);
+ Status findOne(OperationContext* opCtx,
+ const NamespaceString& collectionName,
+ const BSONObj& query,
+ BSONObj* result) final;
+ bool hasOne(OperationContext* opCtx,
+ const NamespaceString& collectionName,
+ const BSONObj& query) final;
+ Status query(OperationContext* opCtx,
+ const NamespaceString& collectionName,
+ const BSONObj& query,
+ const BSONObj& projection,
+ const std::function<void(const BSONObj&)>& resultProcessor) final;
};
} // namespace mongo
diff --git a/src/mongo/db/auth/authz_manager_external_state_local.cpp b/src/mongo/db/auth/authz_manager_external_state_local.cpp
index 89ad8fbe7a5..e530074b5a4 100644
--- a/src/mongo/db/auth/authz_manager_external_state_local.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp
@@ -293,6 +293,25 @@ Status AuthzManagerExternalStateLocal::_getUserDocument(OperationContext* opCtx,
return status;
}
+Status AuthzManagerExternalStateLocal::rolesExist(OperationContext* opCtx,
+ const std::vector<RoleName>& roleNames) {
+ // Perform DB queries for user-defined roles (skipping builtin roles).
+ stdx::unordered_set<RoleName> unknownRoles;
+ for (const auto& roleName : roleNames) {
+ if (!RoleGraph::isBuiltinRole(roleName) &&
+ !hasOne(opCtx, AuthorizationManager::rolesCollectionNamespace, roleName.toBSON())) {
+ unknownRoles.insert(roleName);
+ }
+ }
+
+ // If anything remains, raise it as an unknown role error.
+ if (!unknownRoles.empty()) {
+ return makeRoleNotFoundStatus(unknownRoles);
+ }
+
+ return Status::OK();
+}
+
Status AuthzManagerExternalStateLocal::getRoleDescription(
OperationContext* opCtx,
const RoleName& roleName,
diff --git a/src/mongo/db/auth/authz_manager_external_state_local.h b/src/mongo/db/auth/authz_manager_external_state_local.h
index bd01781fc97..0832d9ea4fa 100644
--- a/src/mongo/db/auth/authz_manager_external_state_local.h
+++ b/src/mongo/db/auth/authz_manager_external_state_local.h
@@ -62,6 +62,7 @@ public:
Status getUserDescription(OperationContext* opCtx,
const UserRequest& user,
BSONObj* result) override;
+ Status rolesExist(OperationContext* opCtx, const std::vector<RoleName>& roleNames) override;
Status getRoleDescription(OperationContext* opCtx,
const RoleName& roleName,
PrivilegeFormat showPrivileges,
@@ -102,6 +103,13 @@ public:
BSONObj* result) = 0;
/**
+ * Checks for the existance of a document matching "query" in "collectionName".
+ */
+ virtual bool hasOne(OperationContext* opCtx,
+ const NamespaceString& collectionName,
+ const BSONObj& query) = 0;
+
+ /**
* Finds all documents matching "query" in "collectionName". For each document returned,
* calls the function resultProcessor on it.
*/
diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.cpp b/src/mongo/db/auth/authz_manager_external_state_mock.cpp
index 1e2c22934b3..57aee1183ea 100644
--- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp
@@ -127,6 +127,14 @@ Status AuthzManagerExternalStateMock::findOne(OperationContext* opCtx,
return Status::OK();
}
+
+bool AuthzManagerExternalStateMock::hasOne(OperationContext* opCtx,
+ const NamespaceString& collectionName,
+ const BSONObj& query) {
+ BSONObjCollection::iterator iter;
+ return _findOneIter(opCtx, collectionName, query, &iter).isOK();
+}
+
Status AuthzManagerExternalStateMock::query(
OperationContext* opCtx,
const NamespaceString& collectionName,
diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.h b/src/mongo/db/auth/authz_manager_external_state_mock.h
index 670c73c924f..cd0a5793c30 100644
--- a/src/mongo/db/auth/authz_manager_external_state_mock.h
+++ b/src/mongo/db/auth/authz_manager_external_state_mock.h
@@ -61,16 +61,21 @@ public:
std::unique_ptr<AuthzSessionExternalState> makeAuthzSessionExternalState(
AuthorizationManager* authzManager) override;
- virtual Status findOne(OperationContext* opCtx,
- const NamespaceString& collectionName,
- const BSONObj& query,
- BSONObj* result);
-
- virtual Status query(OperationContext* opCtx,
- const NamespaceString& collectionName,
- const BSONObj& query,
- const BSONObj& projection, // Currently unused in mock
- const std::function<void(const BSONObj&)>& resultProcessor);
+ Status findOne(OperationContext* opCtx,
+ const NamespaceString& collectionName,
+ const BSONObj& query,
+ BSONObj* result) override;
+
+ bool hasOne(OperationContext* opCtx,
+ const NamespaceString& collectionName,
+ const BSONObj& query) override;
+
+
+ Status query(OperationContext* opCtx,
+ const NamespaceString& collectionName,
+ const BSONObj& query,
+ const BSONObj& projection, // Currently unused in mock
+ const std::function<void(const BSONObj&)>& resultProcessor) override;
/**
* Inserts the given user object into the "admin" database.
diff --git a/src/mongo/db/auth/authz_manager_external_state_s.cpp b/src/mongo/db/auth/authz_manager_external_state_s.cpp
index 95e906a8acc..d43be5722ce 100644
--- a/src/mongo/db/auth/authz_manager_external_state_s.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp
@@ -192,6 +192,57 @@ Status AuthzManagerExternalStateMongos::getUserDescription(OperationContext* opC
}
}
+Status AuthzManagerExternalStateMongos::rolesExist(OperationContext* opCtx,
+ const std::vector<RoleName>& roleNames) try {
+ // Marshall role names into a set before querying so that we don't get a false-negative
+ // from repeated roles only providing one result at the end.
+ stdx::unordered_set<RoleName> roleNameSet(roleNames.cbegin(), roleNames.cend());
+
+ BSONObjBuilder rolesInfoCmd;
+
+ {
+ BSONArrayBuilder rolesArray(rolesInfoCmd.subarrayStart("rolesInfo"));
+ for (const auto& roleName : roleNameSet) {
+ roleName.serializeToBSON(&rolesArray);
+ }
+ rolesArray.doneFast();
+ }
+
+ BSONObjBuilder resultBuilder;
+ if (!Grid::get(opCtx)->catalogClient()->runUserManagementReadCommand(
+ opCtx, "admin", rolesInfoCmd.obj(), &resultBuilder)) {
+ return {ErrorCodes::OperationFailed, "Failed running rolesInfo command on mongod"};
+ }
+
+ auto result = resultBuilder.obj();
+ auto cmdStatus = getStatusFromCommandResult(result);
+ if (!cmdStatus.isOK()) {
+ return {cmdStatus.code(),
+ str::stream() << "Failed running rolesInfo command on mongod: "
+ << cmdStatus.reason()};
+ }
+
+ auto roles = result["roles"];
+ if (roles.type() != Array) {
+ return {ErrorCodes::OperationFailed,
+ "Received invalid response from rolesInfo command on mongod"};
+ }
+
+ if (static_cast<std::size_t>(roles.Obj().nFields()) != roleNameSet.size()) {
+ // One or more missing roles, cross out the ones that do exist, and return error.
+ for (const auto& roleObj : roles.Obj()) {
+ auto roleName = RoleName::parseFromBSON(roleObj);
+ roleNameSet.erase(roleName);
+ }
+
+ return makeRoleNotFoundStatus(roleNameSet);
+ }
+
+ return Status::OK();
+} catch (const AssertionException& ex) {
+ return ex.toStatus();
+}
+
Status AuthzManagerExternalStateMongos::getRoleDescription(
OperationContext* opCtx,
const RoleName& roleName,
diff --git a/src/mongo/db/auth/authz_manager_external_state_s.h b/src/mongo/db/auth/authz_manager_external_state_s.h
index 939a2ca1cb2..4d310c6aa47 100644
--- a/src/mongo/db/auth/authz_manager_external_state_s.h
+++ b/src/mongo/db/auth/authz_manager_external_state_s.h
@@ -49,33 +49,34 @@ class AuthzManagerExternalStateMongos : public AuthzManagerExternalState {
public:
AuthzManagerExternalStateMongos();
- ~AuthzManagerExternalStateMongos() override;
+ ~AuthzManagerExternalStateMongos() final;
- Status initialize(OperationContext* opCtx) override;
+ Status initialize(OperationContext* opCtx) final;
std::unique_ptr<AuthzSessionExternalState> makeAuthzSessionExternalState(
- AuthorizationManager* authzManager) override;
+ AuthorizationManager* authzManager) final;
Status getStoredAuthorizationVersion(OperationContext* opCtx, int* outVersion) override;
+ Status rolesExist(OperationContext* opCtx, const std::vector<RoleName>& roleNames) final;
Status getUserDescription(OperationContext* opCtx,
const UserRequest& user,
- BSONObj* result) override;
+ BSONObj* result) final;
Status getRoleDescription(OperationContext* opCtx,
const RoleName& roleName,
PrivilegeFormat showPrivileges,
AuthenticationRestrictionsFormat,
- BSONObj* result) override;
+ BSONObj* result) final;
Status getRolesDescription(OperationContext* opCtx,
const std::vector<RoleName>& roles,
PrivilegeFormat showPrivileges,
AuthenticationRestrictionsFormat,
- BSONObj* result) override;
+ BSONObj* result) final;
Status getRoleDescriptionsForDB(OperationContext* opCtx,
StringData dbname,
PrivilegeFormat showPrivileges,
AuthenticationRestrictionsFormat,
bool showBuiltinRoles,
- std::vector<BSONObj>* result) override;
+ std::vector<BSONObj>* result) final;
- bool hasAnyPrivilegeDocuments(OperationContext* opCtx) override;
+ bool hasAnyPrivilegeDocuments(OperationContext* opCtx) final;
};
} // namespace mongo
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index fe1841aa8f9..47f5bc48ee7 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -882,11 +882,7 @@ void CmdUMCTyped<CreateUserCommand, void>::Invocation::typedRun(OperationContext
uassertStatusOK(V2UserDocumentParser().checkValidUserDocument(userObj));
// Role existence has to be checked after acquiring the update lock
- for (const auto& role : cmd.getRoles()) {
- BSONObj ignored;
- uassertStatusOK(
- authzManager->getRoleDescription(opCtx, role.getRoleName(dbname), &ignored));
- }
+ uassertStatusOK(authzManager->rolesExist(opCtx, resolvedRoles));
// Audit this event.
auto optCustomData = cmd.getCustomData();
@@ -988,11 +984,8 @@ void CmdUMCTyped<UpdateUserCommand, void>::Invocation::typedRun(OperationContext
// Role existence has to be checked after acquiring the update lock
if (auto roles = cmd.getRoles()) {
- for (const auto& role : roles.get()) {
- BSONObj ignored;
- uassertStatusOK(
- authzManager->getRoleDescription(opCtx, role.getRoleName(dbname), &ignored));
- }
+ auto resolvedRoles = auth::resolveRoleNames(roles.get(), dbname);
+ uassertStatusOK(authzManager->rolesExist(opCtx, resolvedRoles));
}
// Audit this event.
@@ -1094,9 +1087,8 @@ void CmdUMCTyped<GrantRolesToUserCommand, void>::Invocation::typedRun(OperationC
uassertStatusOK(getCurrentUserRoles(opCtx, authzManager, userName, &userRoles));
auto resolvedRoleNames = auth::resolveRoleNames(cmd.getRoles(), dbname);
+ uassertStatusOK(authzManager->rolesExist(opCtx, resolvedRoleNames));
for (const auto& role : resolvedRoleNames) {
- BSONObj roleDoc;
- uassertStatusOK(authzManager->getRoleDescription(opCtx, role, &roleDoc));
userRoles.insert(role);
}
@@ -1130,9 +1122,8 @@ void CmdUMCTyped<RevokeRolesFromUserCommand, void>::Invocation::typedRun(Operati
uassertStatusOK(getCurrentUserRoles(opCtx, authzManager, userName, &userRoles));
auto resolvedUserRoles = auth::resolveRoleNames(cmd.getRoles(), dbname);
+ uassertStatusOK(authzManager->rolesExist(opCtx, resolvedUserRoles));
for (const auto& role : resolvedUserRoles) {
- BSONObj roleDoc;
- uassertStatusOK(authzManager->getRoleDescription(opCtx, role, &roleDoc));
userRoles.erase(role);
}
@@ -1400,8 +1391,7 @@ void CmdUMCTyped<UpdateRoleCommand, void>::Invocation::typedRun(OperationContext
auto lk = uassertStatusOK(requireWritableAuthSchema28SCRAM(opCtx, authzManager));
// Role existence has to be checked after acquiring the update lock
- BSONObj ignored;
- uassertStatusOK(authzManager->getRoleDescription(opCtx, roleName, &ignored));
+ uassertStatusOK(authzManager->rolesExist(opCtx, {roleName}));
if (optRoles) {
uassertStatusOK(checkOkayToGrantRolesToRole(opCtx, roleName, *optRoles, authzManager));
@@ -1660,8 +1650,7 @@ void CmdUMCTyped<DropRoleCommand, void>::Invocation::typedRun(OperationContext*
auto* authzManager = AuthorizationManager::get(serviceContext);
auto lk = uassertStatusOK(requireWritableAuthSchema28SCRAM(opCtx, authzManager));
- BSONObj roleDoc;
- uassertStatusOK(authzManager->getRoleDescription(opCtx, roleName, &roleDoc));
+ uassertStatusOK(authzManager->rolesExist(opCtx, {roleName}));
// From here on, we always want to invalidate the user cache before returning.
auto invalidateGuard = makeGuard([&] {
diff --git a/src/mongo/embedded/embedded_auth_manager.cpp b/src/mongo/embedded/embedded_auth_manager.cpp
index 671fab3c41d..aef2b61d650 100644
--- a/src/mongo/embedded/embedded_auth_manager.cpp
+++ b/src/mongo/embedded/embedded_auth_manager.cpp
@@ -74,6 +74,10 @@ public:
UASSERT_NOT_IMPLEMENTED;
}
+ Status rolesExist(OperationContext*, const std::vector<RoleName>&) override {
+ UASSERT_NOT_IMPLEMENTED;
+ }
+
Status getRoleDescription(OperationContext*,
const RoleName&,
PrivilegeFormat,