diff options
author | Spencer T Brody <spencer@mongodb.com> | 2015-10-12 18:47:37 -0400 |
---|---|---|
committer | Spencer T Brody <spencer@mongodb.com> | 2015-10-13 23:27:06 -0400 |
commit | 110e24cb3571778f4abb53e8f121b14f529307f6 (patch) | |
tree | 988034cf220254503fdaafadb5f8abbe2f7ffc74 /src/mongo/db | |
parent | 3c706c7fcabbb267a29c482b1c016e838ce82588 (diff) | |
download | mongo-110e24cb3571778f4abb53e8f121b14f529307f6.tar.gz |
SERVER-20891 User-initiated writes to the config server must use w:majority write concern
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/commands/user_management_commands.cpp | 189 | ||||
-rw-r--r-- | src/mongo/db/write_concern.cpp | 21 | ||||
-rw-r--r-- | src/mongo/db/write_concern_options.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/write_concern_options.h | 6 |
4 files changed, 121 insertions, 99 deletions
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp index d60c54b35f7..30387107ff4 100644 --- a/src/mongo/db/commands/user_management_commands.cpp +++ b/src/mongo/db/commands/user_management_commands.cpp @@ -532,14 +532,15 @@ Status removePrivilegeDocuments(OperationContext* txn, */ Status writeAuthSchemaVersionIfNeeded(OperationContext* txn, AuthorizationManager* authzManager, - int foundSchemaVersion) { + int foundSchemaVersion, + const BSONObj& writeConcern) { Status status = updateOneAuthzDocument( txn, AuthorizationManager::versionCollectionNamespace, AuthorizationManager::versionDocumentQuery, BSON("$set" << BSON(AuthorizationManager::schemaVersionFieldName << foundSchemaVersion)), - true, // upsert - BSONObj()); // write concern + true, // upsert + writeConcern); if (status == ErrorCodes::NoMatchingDocument) { // SERVER-11492 status = Status::OK(); } @@ -552,7 +553,9 @@ Status writeAuthSchemaVersionIfNeeded(OperationContext* txn, * for the MongoDB 2.6 and 3.0 MongoDB-CR/SCRAM mixed auth mode. * Returns an error otherwise. */ -Status requireAuthSchemaVersion26Final(OperationContext* txn, AuthorizationManager* authzManager) { +Status requireAuthSchemaVersion26Final(OperationContext* txn, + AuthorizationManager* authzManager, + const BSONObj& writeConcern) { int foundSchemaVersion; Status status = authzManager->getAuthorizationVersion(txn, &foundSchemaVersion); if (!status.isOK()) { @@ -567,7 +570,7 @@ Status requireAuthSchemaVersion26Final(OperationContext* txn, AuthorizationManag << AuthorizationManager::schemaVersion26Final << " but found " << foundSchemaVersion); } - return writeAuthSchemaVersionIfNeeded(txn, authzManager, foundSchemaVersion); + return writeAuthSchemaVersionIfNeeded(txn, authzManager, foundSchemaVersion, writeConcern); } /** @@ -712,7 +715,7 @@ public: stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); - status = requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager, args.writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -822,7 +825,7 @@ public: stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager, args.writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -886,26 +889,25 @@ public: int options, string& errmsg, BSONObjBuilder& result) { - ServiceContext* serviceContext = txn->getClient()->getServiceContext(); - stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); - AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = requireAuthSchemaVersion26Final(txn, authzManager); + UserName userName; + BSONObj writeConcern; + Status status = + auth::parseAndValidateDropUserCommand(cmdObj, dbname, &userName, &writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } - - UserName userName; - BSONObj writeConcern; - status = auth::parseAndValidateDropUserCommand(cmdObj, dbname, &userName, &writeConcern); + ServiceContext* serviceContext = txn->getClient()->getServiceContext(); + stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); + AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); + status = requireAuthSchemaVersion26Final(txn, authzManager, writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } - int nMatched; - audit::logDropUser(ClientBasic::getCurrent(), userName); + int nMatched; status = removePrivilegeDocuments(txn, BSON(AuthorizationManager::USER_NAME_FIELD_NAME << userName.getUser() @@ -959,26 +961,24 @@ public: int options, string& errmsg, BSONObjBuilder& result) { - ServiceContext* serviceContext = txn->getClient()->getServiceContext(); - stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); - - AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = requireAuthSchemaVersion26Final(txn, authzManager); + BSONObj writeConcern; + Status status = + auth::parseAndValidateDropAllUsersFromDatabaseCommand(cmdObj, dbname, &writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } + ServiceContext* serviceContext = txn->getClient()->getServiceContext(); + stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); - BSONObj writeConcern; - status = - auth::parseAndValidateDropAllUsersFromDatabaseCommand(cmdObj, dbname, &writeConcern); + AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); + status = requireAuthSchemaVersion26Final(txn, authzManager, writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } - int numRemoved; - audit::logDropAllUsersFromDatabase(ClientBasic::getCurrent(), dbname); + int numRemoved; status = removePrivilegeDocuments(txn, BSON(AuthorizationManager::USER_DB_FIELD_NAME << dbname), writeConcern, @@ -1023,24 +1023,24 @@ public: int options, string& errmsg, BSONObjBuilder& result) { - ServiceContext* serviceContext = txn->getClient()->getServiceContext(); - stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); - - AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = requireAuthSchemaVersion26Final(txn, authzManager); - if (!status.isOK()) { - return appendCommandStatus(result, status); - } - std::string userNameString; std::vector<RoleName> roles; BSONObj writeConcern; - status = auth::parseRolePossessionManipulationCommands( + Status status = auth::parseRolePossessionManipulationCommands( cmdObj, "grantRolesToUser", dbname, &userNameString, &roles, &writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } + ServiceContext* serviceContext = txn->getClient()->getServiceContext(); + stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); + + AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); + status = requireAuthSchemaVersion26Final(txn, authzManager, writeConcern); + if (!status.isOK()) { + return appendCommandStatus(result, status); + } + UserName userName(userNameString, dbname); unordered_set<RoleName> userRoles; status = getCurrentUserRoles(txn, authzManager, userName, &userRoles); @@ -1098,24 +1098,24 @@ public: int options, string& errmsg, BSONObjBuilder& result) { - ServiceContext* serviceContext = txn->getClient()->getServiceContext(); - stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); - - AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = requireAuthSchemaVersion26Final(txn, authzManager); - if (!status.isOK()) { - return appendCommandStatus(result, status); - } - std::string userNameString; std::vector<RoleName> roles; BSONObj writeConcern; - status = auth::parseRolePossessionManipulationCommands( + Status status = auth::parseRolePossessionManipulationCommands( cmdObj, "revokeRolesFromUser", dbname, &userNameString, &roles, &writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } + ServiceContext* serviceContext = txn->getClient()->getServiceContext(); + stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); + + AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); + status = requireAuthSchemaVersion26Final(txn, authzManager, writeConcern); + if (!status.isOK()) { + return appendCommandStatus(result, status); + } + UserName userName(userNameString, dbname); unordered_set<RoleName> userRoles; status = getCurrentUserRoles(txn, authzManager, userName, &userRoles); @@ -1346,7 +1346,7 @@ public: stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager, args.writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1430,7 +1430,7 @@ public: stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager, args.writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1497,24 +1497,24 @@ public: int options, string& errmsg, BSONObjBuilder& result) { - ServiceContext* serviceContext = txn->getClient()->getServiceContext(); - stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); - - AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = requireAuthSchemaVersion26Final(txn, authzManager); - if (!status.isOK()) { - return appendCommandStatus(result, status); - } - RoleName roleName; PrivilegeVector privilegesToAdd; BSONObj writeConcern; - status = auth::parseAndValidateRolePrivilegeManipulationCommands( + Status status = auth::parseAndValidateRolePrivilegeManipulationCommands( cmdObj, "grantPrivilegesToRole", dbname, &roleName, &privilegesToAdd, &writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } + ServiceContext* serviceContext = txn->getClient()->getServiceContext(); + stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); + + AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); + status = requireAuthSchemaVersion26Final(txn, authzManager, writeConcern); + if (!status.isOK()) { + return appendCommandStatus(result, status); + } + if (RoleGraph::isBuiltinRole(roleName)) { return appendCommandStatus( result, @@ -1605,24 +1605,25 @@ public: int options, string& errmsg, BSONObjBuilder& result) { - ServiceContext* serviceContext = txn->getClient()->getServiceContext(); - stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); - - AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = requireAuthSchemaVersion26Final(txn, authzManager); + RoleName roleName; + PrivilegeVector privilegesToRemove; + BSONObj writeConcern; + Status status = + auth::parseAndValidateRolePrivilegeManipulationCommands(cmdObj, + "revokePrivilegesFromRole", + dbname, + &roleName, + &privilegesToRemove, + &writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } - RoleName roleName; - PrivilegeVector privilegesToRemove; - BSONObj writeConcern; - status = auth::parseAndValidateRolePrivilegeManipulationCommands(cmdObj, - "revokePrivilegesFromRole", - dbname, - &roleName, - &privilegesToRemove, - &writeConcern); + ServiceContext* serviceContext = txn->getClient()->getServiceContext(); + stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); + + AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); + status = requireAuthSchemaVersion26Final(txn, authzManager, writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1742,7 +1743,7 @@ public: stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager, writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1815,24 +1816,24 @@ public: int options, string& errmsg, BSONObjBuilder& result) { - ServiceContext* serviceContext = txn->getClient()->getServiceContext(); - stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); - - AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = requireAuthSchemaVersion26Final(txn, authzManager); - if (!status.isOK()) { - return appendCommandStatus(result, status); - } - std::string roleNameString; std::vector<RoleName> rolesToRemove; BSONObj writeConcern; - status = auth::parseRolePossessionManipulationCommands( + Status status = auth::parseRolePossessionManipulationCommands( cmdObj, "revokeRolesFromRole", dbname, &roleNameString, &rolesToRemove, &writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } + ServiceContext* serviceContext = txn->getClient()->getServiceContext(); + stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); + + AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); + status = requireAuthSchemaVersion26Final(txn, authzManager, writeConcern); + if (!status.isOK()) { + return appendCommandStatus(result, status); + } + RoleName roleName(roleNameString, dbname); if (RoleGraph::isBuiltinRole(roleName)) { return appendCommandStatus( @@ -1907,18 +1908,18 @@ public: int options, string& errmsg, BSONObjBuilder& result) { - ServiceContext* serviceContext = txn->getClient()->getServiceContext(); - stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); - - AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = requireAuthSchemaVersion26Final(txn, authzManager); + RoleName roleName; + BSONObj writeConcern; + Status status = auth::parseDropRoleCommand(cmdObj, dbname, &roleName, &writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } - RoleName roleName; - BSONObj writeConcern; - status = auth::parseDropRoleCommand(cmdObj, dbname, &roleName, &writeConcern); + ServiceContext* serviceContext = txn->getClient()->getServiceContext(); + stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); + + AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); + status = requireAuthSchemaVersion26Final(txn, authzManager, writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -2072,7 +2073,7 @@ public: stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager, writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -2697,7 +2698,7 @@ public: stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext)); AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager, args.writeConcern); if (!status.isOK()) { return appendCommandStatus(result, status); } diff --git a/src/mongo/db/write_concern.cpp b/src/mongo/db/write_concern.cpp index f035b3f5bfd..64f2ad068db 100644 --- a/src/mongo/db/write_concern.cpp +++ b/src/mongo/db/write_concern.cpp @@ -130,13 +130,24 @@ Status validateWriteConcern(const WriteConcernOptions& writeConcern) { const repl::ReplicationCoordinator::Mode replMode = repl::getGlobalReplicationCoordinator()->getReplicationMode(); - if (isConfigServer && replMode != repl::ReplicationCoordinator::modeReplSet) { - // SCCC config servers can have a master-slave oplog, but we still don't allow w > 1. - if (writeConcern.wNumNodes > 1) { - return Status(ErrorCodes::BadValue, - "cannot use 'w' > 1 on a sync cluster connection config server host"); + if (isConfigServer) { + if (!writeConcern.validForConfigServers()) { + return Status( + ErrorCodes::BadValue, + str::stream() + << "w:1 and w:'majority' are the only valid write concerns when writing to " + "config servers, got: " << writeConcern.toBSON().toString()); + } + if (replMode == repl::ReplicationCoordinator::modeReplSet && writeConcern.wMode == "") { + invariant(writeConcern.wNumNodes == 1); + return Status( + ErrorCodes::BadValue, + str::stream() + << "w: 'majority' is the only valid write concern when writing to config " + "server replica sets, got: " << writeConcern.toBSON().toString()); } } + if (replMode == repl::ReplicationCoordinator::modeNone) { if (writeConcern.wNumNodes > 1) { return Status(ErrorCodes::BadValue, "cannot use 'w' > 1 when a host is not replicated"); diff --git a/src/mongo/db/write_concern_options.cpp b/src/mongo/db/write_concern_options.cpp index e24f652517d..b099d868a96 100644 --- a/src/mongo/db/write_concern_options.cpp +++ b/src/mongo/db/write_concern_options.cpp @@ -187,4 +187,8 @@ bool WriteConcernOptions::shouldWaitForOtherNodes() const { return !wMode.empty() || wNumNodes > 1; } +bool WriteConcernOptions::validForConfigServers() const { + return wNumNodes == 1 || wMode == kMajority; +} + } // namespace mongo diff --git a/src/mongo/db/write_concern_options.h b/src/mongo/db/write_concern_options.h index a0cb45f8da9..1bac963f16f 100644 --- a/src/mongo/db/write_concern_options.h +++ b/src/mongo/db/write_concern_options.h @@ -87,6 +87,12 @@ public: */ bool shouldWaitForOtherNodes() const; + /** + * Returns true if this is a valid write concern to use against a config server. + * TODO(spencer): Once we stop supporting SCCC config servers, forbid this from allowing w:1 + */ + bool validForConfigServers() const; + void reset() { syncMode = NONE; wNumNodes = 0; |