summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorSpencer Jackson <spencer.jackson@mongodb.com>2017-07-17 11:50:42 -0400
committerSpencer Jackson <spencer.jackson@mongodb.com>2017-07-21 11:33:34 -0400
commit0dd496c83318994d8058b24adf3b75116cd40cd5 (patch)
tree0d86fdaca135cdb0679176501c2df53af7e1e0fa /src/mongo/db
parenta7164c0527ac1f231d12a889bf6d16b264af338e (diff)
downloadmongo-0dd496c83318994d8058b24adf3b75116cd40cd5.tar.gz
SERVER-29177: Add restriction support to createUser
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/auth/SConscript1
-rw-r--r--src/mongo/db/auth/address_restriction.cpp7
-rw-r--r--src/mongo/db/auth/authorization_session.cpp9
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp79
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.cpp8
-rw-r--r--src/mongo/db/auth/user_document_parser_test.cpp18
-rw-r--r--src/mongo/db/auth/user_management_commands_parser.cpp11
-rw-r--r--src/mongo/db/auth/user_management_commands_parser.h1
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp7
9 files changed, 141 insertions, 0 deletions
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index f831c1e774a..e3d2aa04a07 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -264,6 +264,7 @@ env.Library(
],
LIBDEPS=[
'authentication_restriction',
+ '$BUILD_DIR/mongo/db/server_options_core',
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/util/net/network',
'$BUILD_DIR/mongo/idl/idl_parser',
diff --git a/src/mongo/db/auth/address_restriction.cpp b/src/mongo/db/auth/address_restriction.cpp
index e0417749097..d4809cead8c 100644
--- a/src/mongo/db/auth/address_restriction.cpp
+++ b/src/mongo/db/auth/address_restriction.cpp
@@ -30,6 +30,7 @@
#include "mongo/db/auth/address_restriction.h"
#include "mongo/db/auth/address_restriction_gen.h"
+#include "mongo/db/server_options.h"
#include "mongo/stdx/memory.h"
constexpr mongo::StringData mongo::address_restriction_detail::ClientSource::label;
@@ -73,6 +74,12 @@ mongo::StatusWith<mongo::SharedRestrictionDocument> mongo::parseAuthenticationRe
std::unique_ptr<document_type::element_type>>::value,
"SharedRestrictionDocument expected to contain a sequence of unique_ptrs");
+ if (serverGlobalParams.featureCompatibility.version.load() <
+ ServerGlobalParams::FeatureCompatibility::Version::k36) {
+ return Status(ErrorCodes::UnsupportedFormat,
+ "'authenticationRestrictions' requires 3.6 feature compatibility version");
+ }
+
document_type::sequence_type doc;
for (const auto& elem : arr) {
if (elem.type() != Object) {
diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp
index 872ed4332a7..6c09f5f1f1d 100644
--- a/src/mongo/db/auth/authorization_session.cpp
+++ b/src/mongo/db/auth/authorization_session.cpp
@@ -1022,6 +1022,15 @@ void AuthorizationSession::_refreshUserInfoAsNeeded(OperationContext* opCtx) {
<< " from session cache of user information.";
continue; // No need to advance "it" in this case.
}
+ case ErrorCodes::UnsupportedFormat: {
+ // An auth subsystem has explicitly indicated a failure.
+ fassert(40555, _authenticatedUsers.removeAt(it) == user);
+ authMan.releaseUser(user);
+ log() << "Removed user " << name
+ << " from session cache of user information because of refresh failure:"
+ << " '" << status << "'.";
+ continue; // No need to advance "it" in this case.
+ }
default:
// Unrecognized error; assume that it's transient, and continue working with the
// out-of-date privilege data.
diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp
index 82869658ece..d6cd4d686fe 100644
--- a/src/mongo/db/auth/authorization_session_test.cpp
+++ b/src/mongo/db/auth/authorization_session_test.cpp
@@ -42,6 +42,7 @@
#include "mongo/db/json.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
+#include "mongo/db/server_options.h"
#include "mongo/db/service_context_noop.h"
#include "mongo/stdx/memory.h"
#include "mongo/transport/session.h"
@@ -92,6 +93,8 @@ public:
std::unique_ptr<AuthorizationSessionForTest> authzSession;
void setUp() {
+ serverGlobalParams.featureCompatibility.version.store(
+ ServerGlobalParams::FeatureCompatibility::Version::k36);
session = transportLayer.createSession();
client = serviceContext.makeClient("testClient", session);
RestrictionEnvironment::set(
@@ -569,6 +572,82 @@ TEST_F(AuthorizationSessionTest, UseOldUserInfoInFaceOfConnectivityProblems) {
authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert));
}
+TEST_F(AuthorizationSessionTest, AcquireUserFailsWithOldFeatureCompatibilityVersion) {
+ ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(),
+ BSON("user"
+ << "spencer"
+ << "db"
+ << "test"
+ << "credentials"
+ << BSON("MONGODB-CR"
+ << "a")
+ << "roles"
+ << BSON_ARRAY(BSON("role"
+ << "readWrite"
+ << "db"
+ << "test"))
+ << "authenticationRestrictions"
+ << BSON_ARRAY(BSON(
+ "clientSource"
+ << BSON_ARRAY("192.168.0.0/24"
+ << "192.168.2.10")
+ << "serverAddress"
+ << BSON_ARRAY("192.168.0.2")))),
+ BSONObj()));
+
+ serverGlobalParams.featureCompatibility.version.store(
+ ServerGlobalParams::FeatureCompatibility::Version::k34);
+
+ RestrictionEnvironment::set(
+ session,
+ stdx::make_unique<RestrictionEnvironment>(SockAddr("192.168.0.6", 5555, AF_UNSPEC),
+ SockAddr("192.168.0.2", 5555, AF_UNSPEC)));
+
+ ASSERT_NOT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test")));
+}
+
+TEST_F(AuthorizationSessionTest, RefreshRemovesRestrictedUsersDuringFeatureCompatibilityDowngrade) {
+ ASSERT_OK(managerState->insertPrivilegeDocument(
+ _opCtx.get(),
+ BSON("user"
+ << "spencer"
+ << "db"
+ << "test"
+ << "credentials"
+ << BSON("MONGODB-CR"
+ << "a")
+ << "roles"
+ << BSON_ARRAY(BSON("role"
+ << "readWrite"
+ << "db"
+ << "test"))
+ << "authenticationRestrictions"
+ << BSON_ARRAY(BSON("clientSource" << BSON_ARRAY("192.168.0.0/24") << "serverAddress"
+ << BSON_ARRAY("192.168.0.2")))),
+ BSONObj()));
+
+ RestrictionEnvironment::set(
+ session,
+ stdx::make_unique<RestrictionEnvironment>(SockAddr("192.168.0.6", 5555, AF_UNSPEC),
+ SockAddr("192.168.0.2", 5555, AF_UNSPEC)));
+
+ ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test")));
+
+ serverGlobalParams.featureCompatibility.version.store(
+ ServerGlobalParams::FeatureCompatibility::Version::k34);
+
+ ASSERT_TRUE(authzSession->lookupUser(UserName("spencer", "test")));
+ ASSERT_TRUE(
+ authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::find));
+
+ authzManager->invalidateUserCache();
+ authzSession->startRequest(_opCtx.get());
+
+ ASSERT_FALSE(authzSession->lookupUser(UserName("spencer", "test")));
+ ASSERT_FALSE(
+ authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::find));
+}
+
TEST_F(AuthorizationSessionTest, AcquireUserObtainsAndValidatesAuthenticationRestrictions) {
ASSERT_OK(managerState->insertPrivilegeDocument(
_opCtx.get(),
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 ac5793a5f09..ad4236b298b 100644
--- a/src/mongo/db/auth/authz_manager_external_state_local.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp
@@ -37,6 +37,7 @@
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/user_document_parser.h"
#include "mongo/db/operation_context.h"
+#include "mongo/db/server_options.h"
#include "mongo/util/log.h"
#include "mongo/util/mongoutils/str.h"
@@ -252,6 +253,13 @@ Status AuthzManagerExternalStateLocal::_getUserDocument(OperationContext* opCtx,
status =
Status(ErrorCodes::UserNotFound,
mongoutils::str::stream() << "Could not find user " << userName.getFullName());
+ } else if ((*userDoc)["authenticationRestrictions"] &&
+ 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.
+ status = Status(ErrorCodes::UnsupportedFormat,
+ "'authenticationRestrictions' requires 3.6 feature compatibility version");
}
return status;
}
diff --git a/src/mongo/db/auth/user_document_parser_test.cpp b/src/mongo/db/auth/user_document_parser_test.cpp
index 77a0408fd38..12f5bffed87 100644
--- a/src/mongo/db/auth/user_document_parser_test.cpp
+++ b/src/mongo/db/auth/user_document_parser_test.cpp
@@ -38,6 +38,7 @@
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/user_document_parser.h"
#include "mongo/db/jsobj.h"
+#include "mongo/db/server_options.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/net/sock.h"
@@ -231,6 +232,8 @@ public:
V2UserDocumentParser v2parser;
void setUp() {
+ serverGlobalParams.featureCompatibility.version.store(
+ ServerGlobalParams::FeatureCompatibility::Version::k36);
user.reset(new User(UserName("spencer", "test")));
adminUser.reset(new User(UserName("admin", "admin")));
}
@@ -610,6 +613,19 @@ TEST_F(V2UserDocumentParsing, V2RoleExtraction) {
ASSERT_FALSE(roles.more());
}
+TEST_F(V2UserDocumentParsing,
+ V2AuthenticationRestrictionsExtractioniFailsOnOldFeatureCompatibilityVersion) {
+ serverGlobalParams.featureCompatibility.version.store(
+ ServerGlobalParams::FeatureCompatibility::Version::k34);
+ Status status = v2parser.initializeAuthenticationRestrictionsFromUserDocument(
+ BSON("user"
+ << "spencer"
+ << "authenticationRestrictions"
+ << BSON_ARRAY(BSON("clientSource" << BSON_ARRAY("::1")))),
+ user.get());
+ ASSERT_EQ(ErrorCodes::UnsupportedFormat, status.code());
+}
+
TEST_F(V2UserDocumentParsing, V2AuthenticationRestrictionsExtraction) {
const auto emptyArray = BSONArrayBuilder().arr();
const auto emptyObj = BSONObjBuilder().obj();
@@ -688,6 +704,8 @@ TEST_F(V2UserDocumentParsing, V2AuthenticationRestrictionsExtraction) {
}
TEST_F(V2UserDocumentParsing, V2AuthenticationRestrictionsExtractionAndRetreival) {
+ serverGlobalParams.featureCompatibility.version.store(
+ ServerGlobalParams::FeatureCompatibility::Version::k36);
enableIPv6(true);
ASSERT_OK(v2parser.initializeAuthenticationRestrictionsFromUserDocument(
BSON("user"
diff --git a/src/mongo/db/auth/user_management_commands_parser.cpp b/src/mongo/db/auth/user_management_commands_parser.cpp
index d480e7bc271..6a170b59fc9 100644
--- a/src/mongo/db/auth/user_management_commands_parser.cpp
+++ b/src/mongo/db/auth/user_management_commands_parser.cpp
@@ -191,6 +191,7 @@ Status parseCreateOrUpdateUserCommands(const BSONObj& cmdObj,
validFieldNames.insert("digestPassword");
validFieldNames.insert("pwd");
validFieldNames.insert("roles");
+ validFieldNames.insert("authenticationRestrictions");
Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames);
if (!status.isOK()) {
@@ -248,6 +249,16 @@ Status parseCreateOrUpdateUserCommands(const BSONObj& cmdObj,
parsedArgs->hasCustomData = true;
}
+ // Parse authentication restrictions
+ if (cmdObj.hasField("authenticationRestrictions")) {
+ BSONElement element = cmdObj["authenticationRestrictions"];
+ if (element.type() != Array) {
+ return Status(ErrorCodes::BadValue, "authenticationRestrictions must be an array");
+ }
+ parsedArgs->authenticationRestrictions =
+ BSONArray(cmdObj["authenticationRestrictions"].Obj());
+ }
+
// Parse roles
if (cmdObj.hasField("roles")) {
BSONElement rolesElement;
diff --git a/src/mongo/db/auth/user_management_commands_parser.h b/src/mongo/db/auth/user_management_commands_parser.h
index 458490e2105..8057a1061bb 100644
--- a/src/mongo/db/auth/user_management_commands_parser.h
+++ b/src/mongo/db/auth/user_management_commands_parser.h
@@ -52,6 +52,7 @@ struct CreateOrUpdateUserArgs {
BSONObj customData;
bool hasRoles;
std::vector<RoleName> roles;
+ boost::optional<BSONArray> authenticationRestrictions;
CreateOrUpdateUserArgs() : hasHashedPassword(false), hasCustomData(false), hasRoles(false) {}
};
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index 49926a76e53..63da13d8f8b 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -47,6 +47,7 @@
#include "mongo/db/audit.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_manager_global.h"
#include "mongo/db/auth/authorization_session.h"
@@ -695,9 +696,15 @@ public:
}
credentialsBuilder.done();
+ if (args.authenticationRestrictions && !args.authenticationRestrictions->isEmpty()) {
+ credentialsBuilder.append("authenticationRestrictions",
+ *args.authenticationRestrictions);
+ }
+
if (args.hasCustomData) {
userObjBuilder.append("customData", args.customData);
}
+
userObjBuilder.append("roles", rolesVectorToBSONArray(args.roles));
BSONObj userObj = userObjBuilder.obj();