summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp9
-rw-r--r--src/mongo/db/auth/authorization_manager.h19
-rw-r--r--src/mongo/db/auth/authz_manager_external_state.h7
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.cpp184
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.h42
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.cpp50
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.h43
-rw-r--r--src/mongo/db/auth/user_document_parser.cpp54
-rw-r--r--src/mongo/db/auth/user_management_commands_parser.cpp19
-rw-r--r--src/mongo/db/auth/user_management_commands_parser.h17
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp54
11 files changed, 340 insertions, 158 deletions
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp
index 51abb758867..5f72d9c04cd 100644
--- a/src/mongo/db/auth/authorization_manager.cpp
+++ b/src/mongo/db/auth/authorization_manager.cpp
@@ -456,25 +456,28 @@ Status AuthorizationManager::getUserDescription(OperationContext* opCtx,
Status AuthorizationManager::getRoleDescription(OperationContext* opCtx,
const RoleName& roleName,
PrivilegeFormat privileges,
+ AuthenticationRestrictionsFormat restrictions,
BSONObj* result) {
- return _externalState->getRoleDescription(opCtx, roleName, privileges, result);
+ return _externalState->getRoleDescription(opCtx, roleName, privileges, restrictions, result);
}
Status AuthorizationManager::getRolesDescription(OperationContext* opCtx,
const std::vector<RoleName>& roleName,
PrivilegeFormat privileges,
+ AuthenticationRestrictionsFormat restrictions,
BSONObj* result) {
- return _externalState->getRolesDescription(opCtx, roleName, privileges, result);
+ return _externalState->getRolesDescription(opCtx, roleName, privileges, restrictions, result);
}
Status AuthorizationManager::getRoleDescriptionsForDB(OperationContext* opCtx,
const std::string dbname,
PrivilegeFormat privileges,
+ AuthenticationRestrictionsFormat restrictions,
bool showBuiltinRoles,
vector<BSONObj>* result) {
return _externalState->getRoleDescriptionsForDB(
- opCtx, dbname, privileges, showBuiltinRoles, result);
+ opCtx, dbname, privileges, restrictions, showBuiltinRoles, result);
}
Status AuthorizationManager::acquireUserToRefreshSessionCache(OperationContext* opCtx,
diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h
index ab70e324079..e8840838e11 100644
--- a/src/mongo/db/auth/authorization_manager.h
+++ b/src/mongo/db/auth/authorization_manager.h
@@ -68,6 +68,14 @@ struct AuthInfo {
extern AuthInfo internalSecurity; // set at startup and not changed after initialization.
/**
+ * How user management functions should structure the BSON representation of privileges and roles.
+ */
+enum class AuthenticationRestrictionsFormat {
+ kOmit, // AuthenticationRestrictions should not be included in the BSON representation.
+ kShow, // AuthenticationRestrictions should be included in the BSON representation.
+};
+
+/**
* Contains server/cluster-wide information about Authorization.
*/
class AuthorizationManager {
@@ -239,14 +247,24 @@ public:
Status getRoleDescription(OperationContext* opCtx,
const RoleName& roleName,
PrivilegeFormat privilegeFormat,
+ AuthenticationRestrictionsFormat,
BSONObj* result);
/**
+ * Convenience wrapper for getRoleDescription() defaulting formats to kOmit.
+ */
+ Status getRoleDescription(OperationContext* ctx, const RoleName& roleName, BSONObj* result) {
+ return getRoleDescription(
+ ctx, roleName, PrivilegeFormat::kOmit, AuthenticationRestrictionsFormat::kOmit, result);
+ }
+
+ /**
* Delegates method call to the underlying AuthzManagerExternalState.
*/
Status getRolesDescription(OperationContext* opCtx,
const std::vector<RoleName>& roleName,
PrivilegeFormat privilegeFormat,
+ AuthenticationRestrictionsFormat,
BSONObj* result);
/**
@@ -255,6 +273,7 @@ public:
Status getRoleDescriptionsForDB(OperationContext* opCtx,
const std::string dbname,
PrivilegeFormat privilegeFormat,
+ AuthenticationRestrictionsFormat,
bool showBuiltinRoles,
std::vector<BSONObj>* result);
diff --git a/src/mongo/db/auth/authz_manager_external_state.h b/src/mongo/db/auth/authz_manager_external_state.h
index f63e05b818f..51d2e7a4808 100644
--- a/src/mongo/db/auth/authz_manager_external_state.h
+++ b/src/mongo/db/auth/authz_manager_external_state.h
@@ -34,6 +34,7 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/privilege_format.h"
#include "mongo/db/auth/role_name.h"
#include "mongo/db/auth/user.h"
@@ -43,7 +44,6 @@
namespace mongo {
-class AuthorizationManager;
class AuthzSessionExternalState;
class OperationContext;
@@ -112,6 +112,7 @@ public:
virtual Status getRoleDescription(OperationContext* opCtx,
const RoleName& roleName,
PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat,
BSONObj* result) = 0;
/**
@@ -130,6 +131,7 @@ public:
virtual Status getRolesDescription(OperationContext* opCtx,
const std::vector<RoleName>& roles,
PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat,
BSONObj* result) = 0;
/**
@@ -145,8 +147,9 @@ public:
* contain a "warnings" array, with std::string messages describing inconsistencies.
*/
virtual Status getRoleDescriptionsForDB(OperationContext* opCtx,
- const std::string dbname,
+ const std::string& dbname,
PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat,
bool showBuiltinRoles,
std::vector<BSONObj>* result) = 0;
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 ad4236b298b..58b13d7099b 100644
--- a/src/mongo/db/auth/authz_manager_external_state_local.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp
@@ -133,6 +133,14 @@ void addPrivilegeObjectsOrWarningsToArrayElement(mutablebson::Element privileges
}
}
}
+
+void addAuthenticationRestrictionObjectsToArrayElement(
+ mutablebson::Element restrictionsElement,
+ const std::vector<SharedRestrictionDocument>& restrictions) {
+ for (const auto& r : restrictions) {
+ fassert(40560, restrictionsElement.appendArray("", r->toBSON()));
+ }
+}
} // namespace
bool AuthzManagerExternalStateLocal::hasAnyPrivilegeDocuments(OperationContext* opCtx) {
@@ -188,6 +196,21 @@ Status AuthzManagerExternalStateLocal::getUserDescription(OperationContext* opCt
resolveUserRoles(&resultDoc, directRoles);
*result = resultDoc.getObject();
+ const auto isNonEmptyArray = [](const BSONObj& doc, StringData element) {
+ const auto& e = doc[element];
+ return !e.eoo() && (e.type() == Array) && !e.Obj().isEmpty();
+ };
+
+ if ((isNonEmptyArray(*result, "authenticationRestrictions") ||
+ isNonEmptyArray(*result, "inheritedAuthenticationRestrictions")) &&
+ serverGlobalParams.featureCompatibility.version.load() <
+ ServerGlobalParams::FeatureCompatibility::Version::k36) {
+ // Mongos isn't able to evaluate whether documents are valid under the current
+ // featureCompatibilityVersion. We must make the decision before it sees them.
+ return Status(ErrorCodes::UnsupportedFormat,
+ "'authenticationRestrictions' requires 3.6 feature compatibility version");
+ }
+
return Status::OK();
}
@@ -195,45 +218,67 @@ void AuthzManagerExternalStateLocal::resolveUserRoles(mutablebson::Document* use
const std::vector<RoleName>& directRoles) {
unordered_set<RoleName> indirectRoles;
PrivilegeVector allPrivileges;
- bool isRoleGraphInconsistent;
+ std::vector<SharedRestrictionDocument> allAuthenticationRestrictions;
+ bool isRoleGraphConsistent = false;
+
{
stdx::lock_guard<stdx::mutex> lk(_roleGraphMutex);
- isRoleGraphInconsistent = _roleGraphState == roleGraphStateConsistent;
- for (size_t i = 0; i < directRoles.size(); ++i) {
- const RoleName& role(directRoles[i]);
+ isRoleGraphConsistent = _roleGraphState == roleGraphStateConsistent;
+ for (const auto& role : directRoles) {
indirectRoles.insert(role);
- if (isRoleGraphInconsistent) {
+ if (isRoleGraphConsistent) {
for (RoleNameIterator subordinates = _roleGraph.getIndirectSubordinates(role);
subordinates.more();
subordinates.next()) {
indirectRoles.insert(subordinates.get());
}
}
- const PrivilegeVector& rolePrivileges(isRoleGraphInconsistent
- ? _roleGraph.getAllPrivileges(role)
- : _roleGraph.getDirectPrivileges(role));
- for (PrivilegeVector::const_iterator priv = rolePrivileges.begin(),
- end = rolePrivileges.end();
- priv != end;
- ++priv) {
- Privilege::addPrivilegeToPrivilegeVector(&allPrivileges, *priv);
+
+ const auto& currentPrivileges = isRoleGraphConsistent
+ ? _roleGraph.getAllPrivileges(role)
+ : _roleGraph.getDirectPrivileges(role);
+ for (const auto& priv : currentPrivileges) {
+ Privilege::addPrivilegeToPrivilegeVector(&allPrivileges, priv);
+ }
+
+ if (isRoleGraphConsistent) {
+ const auto& currentAuthenticationRestrictions =
+ _roleGraph.getAllAuthenticationRestrictions(role);
+ allAuthenticationRestrictions.insert(allAuthenticationRestrictions.end(),
+ currentAuthenticationRestrictions.begin(),
+ currentAuthenticationRestrictions.end());
+ } else {
+ const auto& dar = _roleGraph.getDirectAuthenticationRestrictions(role);
+ if (dar.get()) {
+ allAuthenticationRestrictions.push_back(dar);
+ }
}
}
}
- mutablebson::Element inheritedRolesElement = userDoc->makeElementArray("inheritedRoles");
- mutablebson::Element privilegesElement = userDoc->makeElementArray("inheritedPrivileges");
- mutablebson::Element warningsElement = userDoc->makeElementArray("warnings");
+ auto warningsElement = userDoc->makeElementArray("warnings");
+
+ auto inheritedRolesElement = userDoc->makeElementArray("inheritedRoles");
fassert(17159, userDoc->root().pushBack(inheritedRolesElement));
+ addRoleNameObjectsToArrayElement(inheritedRolesElement,
+ makeRoleNameIteratorForContainer(indirectRoles));
+
+ auto privilegesElement = userDoc->makeElementArray("inheritedPrivileges");
fassert(17158, userDoc->root().pushBack(privilegesElement));
- if (!isRoleGraphInconsistent) {
+ addPrivilegeObjectsOrWarningsToArrayElement(privilegesElement, warningsElement, allPrivileges);
+
+ auto authenticationRestrictionsElement =
+ userDoc->makeElementArray("inheritedAuthenticationRestrictions");
+ fassert(40558, userDoc->root().pushBack(authenticationRestrictionsElement));
+ addAuthenticationRestrictionObjectsToArrayElement(authenticationRestrictionsElement,
+ allAuthenticationRestrictions);
+
+ if (!isRoleGraphConsistent) {
fassert(17160,
warningsElement.appendString(
"", "Role graph inconsistent, only direct privileges available."));
}
- addRoleNameObjectsToArrayElement(inheritedRolesElement,
- makeRoleNameIteratorForContainer(indirectRoles));
- addPrivilegeObjectsOrWarningsToArrayElement(privilegesElement, warningsElement, allPrivileges);
+
if (warningsElement.hasChildren()) {
fassert(17161, userDoc->root().pushBack(warningsElement));
}
@@ -249,6 +294,7 @@ Status AuthzManagerExternalStateLocal::_getUserDocument(OperationContext* opCtx,
<< AuthorizationManager::USER_DB_FIELD_NAME
<< userName.getDB()),
userDoc);
+
if (status == ErrorCodes::NoMatchingDocument) {
status =
Status(ErrorCodes::UserNotFound,
@@ -264,10 +310,12 @@ Status AuthzManagerExternalStateLocal::_getUserDocument(OperationContext* opCtx,
return status;
}
-Status AuthzManagerExternalStateLocal::getRoleDescription(OperationContext* opCtx,
- const RoleName& roleName,
- PrivilegeFormat showPrivileges,
- BSONObj* result) {
+Status AuthzManagerExternalStateLocal::getRoleDescription(
+ OperationContext* opCtx,
+ const RoleName& roleName,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat showRestrictions,
+ BSONObj* result) {
if (showPrivileges == PrivilegeFormat::kShowAsUserFragment) {
mutablebson::Document resultDoc;
mutablebson::Element rolesElement = resultDoc.makeElementArray("roles");
@@ -279,13 +327,15 @@ Status AuthzManagerExternalStateLocal::getRoleDescription(OperationContext* opCt
return Status::OK();
}
stdx::lock_guard<stdx::mutex> lk(_roleGraphMutex);
- return _getRoleDescription_inlock(roleName, showPrivileges, result);
+ return _getRoleDescription_inlock(roleName, showPrivileges, showRestrictions, result);
}
-Status AuthzManagerExternalStateLocal::getRolesDescription(OperationContext* opCtx,
- const std::vector<RoleName>& roles,
- PrivilegeFormat showPrivileges,
- BSONObj* result) {
+Status AuthzManagerExternalStateLocal::getRolesDescription(
+ OperationContext* opCtx,
+ const std::vector<RoleName>& roles,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat showRestrictions,
+ BSONObj* result) {
if (showPrivileges == PrivilegeFormat::kShowAsUserFragment) {
mutablebson::Document resultDoc;
mutablebson::Element rolesElement = resultDoc.makeElementArray("roles");
@@ -300,7 +350,8 @@ Status AuthzManagerExternalStateLocal::getRolesDescription(OperationContext* opC
BSONArrayBuilder resultBuilder;
for (const RoleName& role : roles) {
BSONObj roleDoc;
- Status status = _getRoleDescription_inlock(role, showPrivileges, &roleDoc);
+ Status status =
+ _getRoleDescription_inlock(role, showPrivileges, showRestrictions, &roleDoc);
if (!status.isOK()) {
if (status.code() == ErrorCodes::RoleNotFound) {
continue;
@@ -313,9 +364,11 @@ Status AuthzManagerExternalStateLocal::getRolesDescription(OperationContext* opC
return Status::OK();
}
-Status AuthzManagerExternalStateLocal::_getRoleDescription_inlock(const RoleName& roleName,
- PrivilegeFormat showPrivileges,
- BSONObj* result) {
+Status AuthzManagerExternalStateLocal::_getRoleDescription_inlock(
+ const RoleName& roleName,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat showRestrictions,
+ BSONObj* result) {
if (!_roleGraph.roleExists(roleName))
return Status(ErrorCodes::RoleNotFound, "No role named " + roleName.toString());
@@ -327,23 +380,39 @@ Status AuthzManagerExternalStateLocal::_getRoleDescription_inlock(const RoleName
17163,
resultDoc.root().appendString(AuthorizationManager::ROLE_DB_FIELD_NAME, roleName.getDB()));
fassert(17267, resultDoc.root().appendBool("isBuiltin", _roleGraph.isBuiltinRole(roleName)));
- mutablebson::Element rolesElement = resultDoc.makeElementArray("roles");
+
+ auto warningsElement = resultDoc.makeElementArray("warnings");
+
+ auto rolesElement = resultDoc.makeElementArray("roles");
fassert(17164, resultDoc.root().pushBack(rolesElement));
- mutablebson::Element inheritedRolesElement = resultDoc.makeElementArray("inheritedRoles");
+ addRoleNameObjectsToArrayElement(rolesElement, _roleGraph.getDirectSubordinates(roleName));
+
+ auto inheritedRolesElement = resultDoc.makeElementArray("inheritedRoles");
fassert(17165, resultDoc.root().pushBack(inheritedRolesElement));
- mutablebson::Element privilegesElement = resultDoc.makeElementArray("privileges");
- mutablebson::Element inheritedPrivilegesElement =
- resultDoc.makeElementArray("inheritedPrivileges");
+
+ auto privilegesElement = resultDoc.makeElementArray("privileges");
if (showPrivileges == PrivilegeFormat::kShowSeparate) {
fassert(17166, resultDoc.root().pushBack(privilegesElement));
}
- mutablebson::Element warningsElement = resultDoc.makeElementArray("warnings");
- addRoleNameObjectsToArrayElement(rolesElement, _roleGraph.getDirectSubordinates(roleName));
+ if (showRestrictions == AuthenticationRestrictionsFormat::kShow) {
+ auto authenticationRestrictionsElement =
+ resultDoc.makeElementArray("authenticationRestrictions");
+ fassert(40559, resultDoc.root().pushBack(authenticationRestrictionsElement));
+
+ const auto& restrictions = _roleGraph.getDirectAuthenticationRestrictions(roleName);
+ if (restrictions.get()) {
+ fassert(40561,
+ authenticationRestrictionsElement.appendArray("", restrictions->toBSON()));
+ }
+ }
+
if (_roleGraphState == roleGraphStateConsistent) {
addRoleNameObjectsToArrayElement(inheritedRolesElement,
_roleGraph.getIndirectSubordinates(roleName));
+
if (showPrivileges == PrivilegeFormat::kShowSeparate) {
+ auto inheritedPrivilegesElement = resultDoc.makeElementArray("inheritedPrivileges");
addPrivilegeObjectsOrWarningsToArrayElement(
privilegesElement, warningsElement, _roleGraph.getDirectPrivileges(roleName));
@@ -352,13 +421,27 @@ Status AuthzManagerExternalStateLocal::_getRoleDescription_inlock(const RoleName
fassert(17323, resultDoc.root().pushBack(inheritedPrivilegesElement));
}
+
+ if (showRestrictions == AuthenticationRestrictionsFormat::kShow) {
+ auto indirectAuthenticationRestrictionsElement =
+ resultDoc.makeElementArray("indirectAuthenticationRestrictions");
+ fassert(40563, resultDoc.root().pushBack(indirectAuthenticationRestrictionsElement));
+
+ for (const auto& restrictions : _roleGraph.getAllAuthenticationRestrictions(roleName)) {
+ fassert(40562,
+ indirectAuthenticationRestrictionsElement.appendArray(
+ "", restrictions->toBSON()));
+ }
+ }
} else if (showPrivileges == PrivilegeFormat::kShowSeparate) {
- warningsElement
- .appendString("", "Role graph state inconsistent; only direct privileges available.")
- .transitional_ignore();
addPrivilegeObjectsOrWarningsToArrayElement(
privilegesElement, warningsElement, _roleGraph.getDirectPrivileges(roleName));
+ fassert(40557,
+ warningsElement.appendString("",
+ "Role graph state inconsistent; only direct "
+ "privileges and restrictions available."));
}
+
if (warningsElement.hasChildren()) {
fassert(17167, resultDoc.root().pushBack(warningsElement));
}
@@ -366,11 +449,13 @@ Status AuthzManagerExternalStateLocal::_getRoleDescription_inlock(const RoleName
return Status::OK();
}
-Status AuthzManagerExternalStateLocal::getRoleDescriptionsForDB(OperationContext* opCtx,
- const std::string dbname,
- PrivilegeFormat showPrivileges,
- bool showBuiltinRoles,
- vector<BSONObj>* result) {
+Status AuthzManagerExternalStateLocal::getRoleDescriptionsForDB(
+ OperationContext* opCtx,
+ const std::string& dbname,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat showRestrictions,
+ bool showBuiltinRoles,
+ vector<BSONObj>* result) {
if (showPrivileges == PrivilegeFormat::kShowAsUserFragment) {
return Status(ErrorCodes::IllegalOperation,
"Cannot get user fragment for all roles in a database");
@@ -382,7 +467,8 @@ Status AuthzManagerExternalStateLocal::getRoleDescriptionsForDB(OperationContext
continue;
}
BSONObj roleDoc;
- Status status = _getRoleDescription_inlock(it.get(), showPrivileges, &roleDoc);
+ Status status =
+ _getRoleDescription_inlock(it.get(), showPrivileges, showRestrictions, &roleDoc);
if (!status.isOK()) {
return status;
}
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 d33b8059084..292eae07f00 100644
--- a/src/mongo/db/auth/authz_manager_external_state_local.h
+++ b/src/mongo/db/auth/authz_manager_external_state_local.h
@@ -55,25 +55,28 @@ class AuthzManagerExternalStateLocal : public AuthzManagerExternalState {
public:
virtual ~AuthzManagerExternalStateLocal() = default;
- virtual Status initialize(OperationContext* opCtx);
-
- virtual Status getStoredAuthorizationVersion(OperationContext* opCtx, int* outVersion);
- virtual Status getUserDescription(OperationContext* opCtx,
- const UserName& userName,
- BSONObj* result);
- virtual Status getRoleDescription(OperationContext* opCtx,
- const RoleName& roleName,
- PrivilegeFormat showPrivileges,
- BSONObj* result);
- virtual Status getRolesDescription(OperationContext* opCtx,
- const std::vector<RoleName>& roles,
- PrivilegeFormat showPrivileges,
- BSONObj* result);
- virtual Status getRoleDescriptionsForDB(OperationContext* opCtx,
- const std::string dbname,
- PrivilegeFormat showPrivileges,
- bool showBuiltinRoles,
- std::vector<BSONObj>* result);
+ Status initialize(OperationContext* opCtx) override;
+
+ Status getStoredAuthorizationVersion(OperationContext* opCtx, int* outVersion) override;
+ Status getUserDescription(OperationContext* opCtx,
+ const UserName& userName,
+ BSONObj* result) override;
+ Status getRoleDescription(OperationContext* opCtx,
+ const RoleName& roleName,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat,
+ BSONObj* result) override;
+ Status getRolesDescription(OperationContext* opCtx,
+ const std::vector<RoleName>& roles,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat,
+ BSONObj* result) override;
+ Status getRoleDescriptionsForDB(OperationContext* opCtx,
+ const std::string& dbname,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat,
+ bool showBuiltinRoles,
+ std::vector<BSONObj>* result) override;
bool hasAnyPrivilegeDocuments(OperationContext* opCtx) override;
@@ -139,6 +142,7 @@ private:
Status _getRoleDescription_inlock(const RoleName& roleName,
PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat showRestrictions,
BSONObj* result);
/**
* Eventually consistent, in-memory representation of all roles in the system (both
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 d941b3f0557..852e66fda7a 100644
--- a/src/mongo/db/auth/authz_manager_external_state_s.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp
@@ -67,13 +67,15 @@ std::string rolesFieldName(PrivilegeFormat showPrivileges) {
/**
* Attches a string representation of a PrivilegeFormat to the provided BSONObjBuilder.
*/
-void addShowPrivilegesToBuilder(BSONObjBuilder* builder, PrivilegeFormat showPrivileges) {
- if (showPrivileges == PrivilegeFormat::kShowSeparate) {
- builder->append("showPrivileges", true);
- } else if (showPrivileges == PrivilegeFormat::kShowAsUserFragment) {
+void addShowToBuilder(BSONObjBuilder* builder,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat showRestrictions) {
+ if (showPrivileges == PrivilegeFormat::kShowAsUserFragment) {
builder->append("showPrivileges", "asUserfragment");
} else {
- builder->append("showPrivileges", false);
+ builder->append("showPrivileges", showPrivileges == PrivilegeFormat::kShowSeparate);
+ builder->append("showAuthenticationRestrictions",
+ showRestrictions == AuthenticationRestrictionsFormat::kShow);
}
}
@@ -204,17 +206,19 @@ Status AuthzManagerExternalStateMongos::getUserDescription(OperationContext* opC
}
}
-Status AuthzManagerExternalStateMongos::getRoleDescription(OperationContext* opCtx,
- const RoleName& roleName,
- PrivilegeFormat showPrivileges,
- BSONObj* result) {
+Status AuthzManagerExternalStateMongos::getRoleDescription(
+ OperationContext* opCtx,
+ const RoleName& roleName,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat showRestrictions,
+ BSONObj* result) {
BSONObjBuilder rolesInfoCmd;
rolesInfoCmd.append("rolesInfo",
BSON_ARRAY(BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME
<< roleName.getRole()
<< AuthorizationManager::ROLE_DB_FIELD_NAME
<< roleName.getDB())));
- addShowPrivilegesToBuilder(&rolesInfoCmd, showPrivileges);
+ addShowToBuilder(&rolesInfoCmd, showPrivileges, showRestrictions);
BSONObjBuilder builder;
const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementReadCommand(
@@ -239,10 +243,12 @@ Status AuthzManagerExternalStateMongos::getRoleDescription(OperationContext* opC
*result = foundRoles[0].Obj().getOwned();
return Status::OK();
}
-Status AuthzManagerExternalStateMongos::getRolesDescription(OperationContext* opCtx,
- const std::vector<RoleName>& roles,
- PrivilegeFormat showPrivileges,
- BSONObj* result) {
+Status AuthzManagerExternalStateMongos::getRolesDescription(
+ OperationContext* opCtx,
+ const std::vector<RoleName>& roles,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat showRestrictions,
+ BSONObj* result) {
BSONArrayBuilder rolesInfoCmdArray;
for (const RoleName& roleName : roles) {
@@ -254,7 +260,7 @@ Status AuthzManagerExternalStateMongos::getRolesDescription(OperationContext* op
BSONObjBuilder rolesInfoCmd;
rolesInfoCmd.append("rolesInfo", rolesInfoCmdArray.arr());
- addShowPrivilegesToBuilder(&rolesInfoCmd, showPrivileges);
+ addShowToBuilder(&rolesInfoCmd, showPrivileges, showRestrictions);
BSONObjBuilder builder;
const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementReadCommand(
@@ -273,14 +279,16 @@ Status AuthzManagerExternalStateMongos::getRolesDescription(OperationContext* op
return Status::OK();
}
-Status AuthzManagerExternalStateMongos::getRoleDescriptionsForDB(OperationContext* opCtx,
- const std::string dbname,
- PrivilegeFormat showPrivileges,
- bool showBuiltinRoles,
- std::vector<BSONObj>* result) {
+Status AuthzManagerExternalStateMongos::getRoleDescriptionsForDB(
+ OperationContext* opCtx,
+ const std::string& dbname,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat showRestrictions,
+ bool showBuiltinRoles,
+ std::vector<BSONObj>* result) {
BSONObjBuilder rolesInfoCmd;
rolesInfoCmd << "rolesInfo" << 1 << "showBuiltinRoles" << showBuiltinRoles;
- addShowPrivilegesToBuilder(&rolesInfoCmd, showPrivileges);
+ addShowToBuilder(&rolesInfoCmd, showPrivileges, showRestrictions);
BSONObjBuilder builder;
const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementReadCommand(
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 3ae98503aad..5cfff629074 100644
--- a/src/mongo/db/auth/authz_manager_external_state_s.h
+++ b/src/mongo/db/auth/authz_manager_external_state_s.h
@@ -33,7 +33,9 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authz_manager_external_state.h"
+#include "mongo/db/auth/privilege_format.h"
#include "mongo/db/auth/user_name.h"
#include "mongo/stdx/functional.h"
@@ -48,28 +50,31 @@ class AuthzManagerExternalStateMongos : public AuthzManagerExternalState {
public:
AuthzManagerExternalStateMongos();
- virtual ~AuthzManagerExternalStateMongos();
+ ~AuthzManagerExternalStateMongos() override;
- virtual Status initialize(OperationContext* opCtx);
+ Status initialize(OperationContext* opCtx) override;
std::unique_ptr<AuthzSessionExternalState> makeAuthzSessionExternalState(
AuthorizationManager* authzManager) override;
- virtual Status getStoredAuthorizationVersion(OperationContext* opCtx, int* outVersion);
- virtual Status getUserDescription(OperationContext* opCtx,
- const UserName& userName,
- BSONObj* result);
- virtual Status getRoleDescription(OperationContext* opCtx,
- const RoleName& roleName,
- PrivilegeFormat showPrivileges,
- BSONObj* result);
- virtual Status getRolesDescription(OperationContext* opCtx,
- const std::vector<RoleName>& roles,
- PrivilegeFormat showPrivileges,
- BSONObj* result);
- virtual Status getRoleDescriptionsForDB(OperationContext* opCtx,
- const std::string dbname,
- PrivilegeFormat showPrivileges,
- bool showBuiltinRoles,
- std::vector<BSONObj>* result);
+ Status getStoredAuthorizationVersion(OperationContext* opCtx, int* outVersion) override;
+ Status getUserDescription(OperationContext* opCtx,
+ const UserName& userName,
+ BSONObj* result) override;
+ Status getRoleDescription(OperationContext* opCtx,
+ const RoleName& roleName,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat,
+ BSONObj* result) override;
+ Status getRolesDescription(OperationContext* opCtx,
+ const std::vector<RoleName>& roles,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat,
+ BSONObj* result) override;
+ Status getRoleDescriptionsForDB(OperationContext* opCtx,
+ const std::string& dbname,
+ PrivilegeFormat showPrivileges,
+ AuthenticationRestrictionsFormat,
+ bool showBuiltinRoles,
+ std::vector<BSONObj>* result) override;
bool hasAnyPrivilegeDocuments(OperationContext* opCtx) override;
};
diff --git a/src/mongo/db/auth/user_document_parser.cpp b/src/mongo/db/auth/user_document_parser.cpp
index 9ac0fd3089a..f1325910d2b 100644
--- a/src/mongo/db/auth/user_document_parser.cpp
+++ b/src/mongo/db/auth/user_document_parser.cpp
@@ -60,6 +60,8 @@ const std::string MONGODB_CR_CREDENTIAL_FIELD_NAME = "MONGODB-CR";
const std::string SCRAM_CREDENTIAL_FIELD_NAME = "SCRAM-SHA-1";
const std::string MONGODB_EXTERNAL_CREDENTIAL_FIELD_NAME = "external";
constexpr StringData AUTHENTICATION_RESTRICTIONS_FIELD_NAME = "authenticationRestrictions"_sd;
+constexpr StringData INHERITED_AUTHENTICATION_RESTRICTIONS_FIELD_NAME =
+ "inheritedAuthenticationRestrictions"_sd;
inline Status _badValue(const char* reason, int location) {
return Status(ErrorCodes::BadValue, reason, location);
@@ -453,25 +455,53 @@ Status V2UserDocumentParser::parseRoleVector(const BSONArray& rolesArray,
Status V2UserDocumentParser::initializeAuthenticationRestrictionsFromUserDocument(
const BSONObj& privDoc, User* user) const {
+ RestrictionDocuments::sequence_type restrictionVector;
+
+ // Restrictions on the user
const auto authenticationRestrictions = privDoc[AUTHENTICATION_RESTRICTIONS_FIELD_NAME];
- if (authenticationRestrictions.eoo()) {
- return Status::OK();
- }
+ if (!authenticationRestrictions.eoo()) {
+ if (authenticationRestrictions.type() != Array) {
+ return Status(ErrorCodes::UnsupportedFormat,
+ "'authenticationRestrictions' field must be an array");
+ }
- if (authenticationRestrictions.type() != Array) {
- return Status(ErrorCodes::UnsupportedFormat,
- "'authenticationRestrictions' field must be an array");
+ auto restrictions =
+ parseAuthenticationRestriction(BSONArray(authenticationRestrictions.Obj()));
+ if (!restrictions.isOK()) {
+ return restrictions.getStatus();
+ }
+
+ restrictionVector.push_back(restrictions.getValue());
}
- auto restrictions = parseAuthenticationRestriction(BSONArray(authenticationRestrictions.Obj()));
- if (!restrictions.isOK()) {
- return restrictions.getStatus();
+ // Restrictions from roles
+ const auto inherited = privDoc[INHERITED_AUTHENTICATION_RESTRICTIONS_FIELD_NAME];
+ if (!inherited.eoo()) {
+ if (inherited.type() != Array) {
+ return Status(ErrorCodes::UnsupportedFormat,
+ "'inheritedAuthenticationRestrictions' field must be an array");
+ }
+
+ for (const auto& roleRestriction : BSONArray(inherited.Obj())) {
+ if (roleRestriction.type() != Array) {
+ return Status(ErrorCodes::UnsupportedFormat,
+ "'inheritedAuthenticationRestrictions' sub-fields must be arrays");
+ }
+
+ auto roleRestrictionDoc =
+ parseAuthenticationRestriction(BSONArray(roleRestriction.Obj()));
+ if (!roleRestrictionDoc.isOK()) {
+ return roleRestrictionDoc.getStatus();
+ }
+
+ restrictionVector.push_back(roleRestrictionDoc.getValue());
+ }
}
- if (user != nullptr) {
- user->setRestrictions(
- RestrictionDocuments(RestrictionDocuments::sequence_type{restrictions.getValue()}));
+ if (user) {
+ user->setRestrictions(RestrictionDocuments(restrictionVector));
}
+
return Status::OK();
}
diff --git a/src/mongo/db/auth/user_management_commands_parser.cpp b/src/mongo/db/auth/user_management_commands_parser.cpp
index 6a170b59fc9..e712ad27cba 100644
--- a/src/mongo/db/auth/user_management_commands_parser.cpp
+++ b/src/mongo/db/auth/user_management_commands_parser.cpp
@@ -367,6 +367,7 @@ Status parseRolesInfoCommand(const BSONObj& cmdObj, StringData dbname, RolesInfo
unordered_set<std::string> validFieldNames;
validFieldNames.insert("rolesInfo");
validFieldNames.insert("showPrivileges");
+ validFieldNames.insert("showAuthenticationRestrictions");
validFieldNames.insert("showBuiltinRoles");
Status status = _checkNoExtraFields(cmdObj, "rolesInfo", validFieldNames);
@@ -411,6 +412,24 @@ Status parseRolesInfoCommand(const BSONObj& cmdObj, StringData dbname, RolesInfo
<< showPrivileges.toString());
}
+ const auto showAuthenticationRestrictions = cmdObj["showAuthenticationRestrictions"];
+ if (showAuthenticationRestrictions.eoo()) {
+ parsedArgs->authenticationRestrictionsFormat = AuthenticationRestrictionsFormat::kOmit;
+ } else if (parsedArgs->privilegeFormat == PrivilegeFormat::kShowAsUserFragment) {
+ return Status(
+ ErrorCodes::UnsupportedFormat,
+ "showAuthenticationRestrictions may not be used with showPrivileges='asUserFragment'");
+ } else {
+ bool show;
+ status = bsonExtractBooleanField(cmdObj, "showAuthenticationRestrictions", &show);
+ if (!status.isOK()) {
+ return status;
+ }
+ parsedArgs->authenticationRestrictionsFormat = show
+ ? AuthenticationRestrictionsFormat::kShow
+ : AuthenticationRestrictionsFormat::kOmit;
+ }
+
status = bsonExtractBooleanFieldWithDefault(
cmdObj, "showBuiltinRoles", false, &parsedArgs->showBuiltinRoles);
if (!status.isOK()) {
diff --git a/src/mongo/db/auth/user_management_commands_parser.h b/src/mongo/db/auth/user_management_commands_parser.h
index 8057a1061bb..5c942a97a09 100644
--- a/src/mongo/db/auth/user_management_commands_parser.h
+++ b/src/mongo/db/auth/user_management_commands_parser.h
@@ -34,6 +34,7 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
#include "mongo/base/string_data.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/privilege.h"
#include "mongo/db/auth/privilege_format.h"
#include "mongo/db/auth/role_name.h"
@@ -114,11 +115,11 @@ Status parseUsersInfoCommand(const BSONObj& cmdObj, StringData dbname, UsersInfo
struct RolesInfoArgs {
std::vector<RoleName> roleNames;
- bool allForDB;
- PrivilegeFormat privilegeFormat;
- bool showBuiltinRoles;
- RolesInfoArgs()
- : allForDB(false), privilegeFormat(PrivilegeFormat::kOmit), showBuiltinRoles(false) {}
+ bool allForDB = false;
+ PrivilegeFormat privilegeFormat = PrivilegeFormat::kOmit;
+ AuthenticationRestrictionsFormat authenticationRestrictionsFormat =
+ AuthenticationRestrictionsFormat::kOmit;
+ bool showBuiltinRoles = false;
};
/**
@@ -129,12 +130,10 @@ Status parseRolesInfoCommand(const BSONObj& cmdObj, StringData dbname, RolesInfo
struct CreateOrUpdateRoleArgs {
RoleName roleName;
- bool hasRoles;
+ bool hasRoles = false;
std::vector<RoleName> roles;
- bool hasPrivileges;
+ bool hasPrivileges = false;
PrivilegeVector privileges;
-
- CreateOrUpdateRoleArgs() : hasRoles(false), hasPrivileges(false) {}
};
/**
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index d1d188c1274..293c6d83fd4 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -178,8 +178,7 @@ Status checkOkayToGrantRolesToRole(OperationContext* opCtx,
}
BSONObj roleToAddDoc;
- Status status = authzManager->getRoleDescription(
- opCtx, roleToAdd, PrivilegeFormat::kOmit, &roleToAddDoc);
+ Status status = authzManager->getRoleDescription(opCtx, roleToAdd, &roleToAddDoc);
if (status == ErrorCodes::RoleNotFound) {
return Status(ErrorCodes::RoleNotFound,
"Cannot grant nonexistent role " + roleToAdd.toString());
@@ -728,8 +727,7 @@ public:
// Role existence has to be checked after acquiring the update lock
for (size_t i = 0; i < args.roles.size(); ++i) {
BSONObj ignored;
- status = authzManager->getRoleDescription(
- opCtx, args.roles[i], PrivilegeFormat::kOmit, &ignored);
+ status = authzManager->getRoleDescription(opCtx, args.roles[i], &ignored);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -867,8 +865,7 @@ public:
if (args.hasRoles) {
for (size_t i = 0; i < args.roles.size(); ++i) {
BSONObj ignored;
- status = authzManager->getRoleDescription(
- opCtx, args.roles[i], PrivilegeFormat::kOmit, &ignored);
+ status = authzManager->getRoleDescription(opCtx, args.roles[i], &ignored);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -1069,8 +1066,7 @@ public:
for (vector<RoleName>::iterator it = roles.begin(); it != roles.end(); ++it) {
RoleName& roleName = *it;
BSONObj roleDoc;
- status =
- authzManager->getRoleDescription(opCtx, roleName, PrivilegeFormat::kOmit, &roleDoc);
+ status = authzManager->getRoleDescription(opCtx, roleName, &roleDoc);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -1142,8 +1138,7 @@ public:
for (vector<RoleName>::iterator it = roles.begin(); it != roles.end(); ++it) {
RoleName& roleName = *it;
BSONObj roleDoc;
- status =
- authzManager->getRoleDescription(opCtx, roleName, PrivilegeFormat::kOmit, &roleDoc);
+ status = authzManager->getRoleDescription(opCtx, roleName, &roleDoc);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -1455,8 +1450,7 @@ public:
// Role existence has to be checked after acquiring the update lock
BSONObj ignored;
- status = authzManager->getRoleDescription(
- opCtx, args.roleName, PrivilegeFormat::kOmit, &ignored);
+ status = authzManager->getRoleDescription(opCtx, args.roleName, &ignored);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -1545,8 +1539,11 @@ public:
}
BSONObj roleDoc;
- status = authzManager->getRoleDescription(
- opCtx, roleName, PrivilegeFormat::kShowSeparate, &roleDoc);
+ status = authzManager->getRoleDescription(opCtx,
+ roleName,
+ PrivilegeFormat::kShowSeparate,
+ AuthenticationRestrictionsFormat::kOmit,
+ &roleDoc);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -1646,8 +1643,11 @@ public:
}
BSONObj roleDoc;
- status = authzManager->getRoleDescription(
- opCtx, roleName, PrivilegeFormat::kShowSeparate, &roleDoc);
+ status = authzManager->getRoleDescription(opCtx,
+ roleName,
+ PrivilegeFormat::kShowSeparate,
+ AuthenticationRestrictionsFormat::kOmit,
+ &roleDoc);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -1757,8 +1757,7 @@ public:
// Role existence has to be checked after acquiring the update lock
BSONObj roleDoc;
- status =
- authzManager->getRoleDescription(opCtx, roleName, PrivilegeFormat::kOmit, &roleDoc);
+ status = authzManager->getRoleDescription(opCtx, roleName, &roleDoc);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -1846,8 +1845,7 @@ public:
}
BSONObj roleDoc;
- status =
- authzManager->getRoleDescription(opCtx, roleName, PrivilegeFormat::kOmit, &roleDoc);
+ status = authzManager->getRoleDescription(opCtx, roleName, &roleDoc);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -1932,8 +1930,7 @@ public:
}
BSONObj roleDoc;
- status =
- authzManager->getRoleDescription(opCtx, roleName, PrivilegeFormat::kOmit, &roleDoc);
+ status = authzManager->getRoleDescription(opCtx, roleName, &roleDoc);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -2217,7 +2214,12 @@ public:
if (args.allForDB) {
std::vector<BSONObj> rolesDocs;
status = getGlobalAuthorizationManager()->getRoleDescriptionsForDB(
- opCtx, dbname, args.privilegeFormat, args.showBuiltinRoles, &rolesDocs);
+ opCtx,
+ dbname,
+ args.privilegeFormat,
+ args.authenticationRestrictionsFormat,
+ args.showBuiltinRoles,
+ &rolesDocs);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}
@@ -2236,7 +2238,11 @@ public:
} else {
BSONObj roleDetails;
status = getGlobalAuthorizationManager()->getRolesDescription(
- opCtx, args.roleNames, args.privilegeFormat, &roleDetails);
+ opCtx,
+ args.roleNames,
+ args.privilegeFormat,
+ args.authenticationRestrictionsFormat,
+ &roleDetails);
if (!status.isOK()) {
return appendCommandStatus(result, status);
}