diff options
author | Spencer Jackson <spencer.jackson@mongodb.com> | 2017-07-17 11:50:42 -0400 |
---|---|---|
committer | Spencer Jackson <spencer.jackson@mongodb.com> | 2017-07-21 11:33:34 -0400 |
commit | 0dd496c83318994d8058b24adf3b75116cd40cd5 (patch) | |
tree | 0d86fdaca135cdb0679176501c2df53af7e1e0fa /src/mongo/db | |
parent | a7164c0527ac1f231d12a889bf6d16b264af338e (diff) | |
download | mongo-0dd496c83318994d8058b24adf3b75116cd40cd5.tar.gz |
SERVER-29177: Add restriction support to createUser
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/auth/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/auth/address_restriction.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_session.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_session_test.cpp | 79 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_local.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/auth/user_document_parser_test.cpp | 18 | ||||
-rw-r--r-- | src/mongo/db/auth/user_management_commands_parser.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/auth/user_management_commands_parser.h | 1 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.cpp | 7 |
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(); |