summaryrefslogtreecommitdiff
path: root/src/mongo/db/auth
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2020-08-07 17:20:40 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-08-20 17:20:11 +0000
commit526230bafa6e5a49f5783507734fba93486c19ae (patch)
tree0368297ed96c038934c356259c901e3c931643dc /src/mongo/db/auth
parentfbde2a22dab3eaf64c5aec542811be954faaf7e1 (diff)
downloadmongo-526230bafa6e5a49f5783507734fba93486c19ae.tar.gz
SERVER-50187 Use AuthzManagerExternalState::roleExists() to simplify role checks
Diffstat (limited to 'src/mongo/db/auth')
-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
13 files changed, 169 insertions, 28 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