summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorSpencer T Brody <spencer@mongodb.com>2015-10-12 18:47:37 -0400
committerSpencer T Brody <spencer@mongodb.com>2015-10-13 23:27:06 -0400
commit110e24cb3571778f4abb53e8f121b14f529307f6 (patch)
tree988034cf220254503fdaafadb5f8abbe2f7ffc74 /src/mongo/db
parent3c706c7fcabbb267a29c482b1c016e838ce82588 (diff)
downloadmongo-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.cpp189
-rw-r--r--src/mongo/db/write_concern.cpp21
-rw-r--r--src/mongo/db/write_concern_options.cpp4
-rw-r--r--src/mongo/db/write_concern_options.h6
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;