summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/auth/auth1.js8
-rw-r--r--jstests/auth/renameSystemCollections.js14
-rw-r--r--jstests/auth/show_log_auth.js8
-rw-r--r--jstests/auth/system_user_privileges.js3
-rw-r--r--jstests/sharding/auth.js2
-rw-r--r--src/mongo/db/commands.cpp49
-rw-r--r--src/mongo/db/commands.h20
-rw-r--r--src/mongo/db/dbcommands.cpp29
-rw-r--r--src/mongo/s/s_only.cpp31
9 files changed, 96 insertions, 68 deletions
diff --git a/jstests/auth/auth1.js b/jstests/auth/auth1.js
index 0a995ea9655..ad5a579feb8 100644
--- a/jstests/auth/auth1.js
+++ b/jstests/auth/auth1.js
@@ -26,9 +26,11 @@ db.getSisterDB( "admin" ).addUser( "super", "super" );
assert.throws( function() { t.findOne() }, [], "read without login" );
print("make sure we can't run certain commands w/out auth");
-var errmsg = "unauthorized";
-assert.eq(db.runCommand({eval : "function() { return 1; }"}).errmsg, errmsg);
-assert.eq(db.adminCommand({getLog : "global"}).errmsg, errmsg);
+var codeUnauthorized = 13;
+var rslt = db.runCommand({eval : "function() { return 1; }"});
+assert.eq(rslt.code, codeUnauthorized, tojson(rslt));
+var rslt = db.runCommand({getLog : "global"});
+assert.eq(rslt.code, codeUnauthorized, tojson(rslt));
assert(!db.auth("eliot", "eliot2"), "auth succeeded with wrong password");
assert(db.auth("eliot", "eliot"), "auth failed");
diff --git a/jstests/auth/renameSystemCollections.js b/jstests/auth/renameSystemCollections.js
index 20296070bb3..96ea309b3d3 100644
--- a/jstests/auth/renameSystemCollections.js
+++ b/jstests/auth/renameSystemCollections.js
@@ -5,6 +5,8 @@ var adminDB = conn.getDB("admin");
var testDB = conn.getDB("testdb");
var testDB2 = conn.getDB("testdb2");
+var CodeUnauthorized = 13;
+
testDB.addUser({user:'spencer',
pwd:'password',
roles:['readWrite']});
@@ -24,13 +26,13 @@ userAdminConn.getDB('admin').addUser({user:'readWriteAdmin',
testDB.auth('spencer', 'password');
res = testDB.system.profile.renameCollection("profile");
assert.eq(0, res.ok);
-assert.eq("unauthorized", res.errmsg);
+assert.eq(CodeUnauthorized, res.code);
// Test that a readWrite user can't rename system.users to something they can read.
var res = testDB.system.users.renameCollection("users");
assert.eq(0, res.ok);
-assert.eq("unauthorized", res.errmsg);
+assert.eq(CodeUnauthorized, res.code);
assert.eq(0, testDB.users.count());
@@ -40,7 +42,7 @@ testDB.users.insert({user:'backdoor',
roles:'userAdmin'});
res = testDB.users.renameCollection("system.users", true);
assert.eq(0, res.ok);
-assert.eq("unauthorized", res.errmsg);
+assert.eq(CodeUnauthorized, res.code);
assert.eq(null, userAdminConn.getDB('testdb').system.users.findOne({user:'backdoor'}));
@@ -51,7 +53,7 @@ testDB2.users.insert({user:'backdoor',
roles:'userAdmin'});
res = testDB2.users.renameCollection("system.users");
assert.eq(0, res.ok);
-assert.eq("unauthorized", res.errmsg);
+assert.eq(CodeUnauthorized, res.code);
assert.eq(0, userAdminConn.getDB('testdb2').system.users.count());
@@ -59,7 +61,7 @@ assert.eq(0, userAdminConn.getDB('testdb2').system.users.count());
testDB2.users.drop();
var res = adminDB.runCommand({renameCollection:'testdb.system.users', to:'testdb2.users'});
assert.eq(0, res.ok);
-assert.eq("unauthorized", res.errmsg);
+assert.eq(CodeUnauthorized, res.code);
assert.eq(0, testDB2.users.count());
@@ -67,7 +69,7 @@ assert.eq(0, testDB2.users.count());
testDB.users.drop();
var res = userAdminConn.getDB('testdb').system.users.renameCollection("users");
assert.eq(0, res.ok);
-assert.eq("unauthorized", res.errmsg);
+assert.eq(CodeUnauthorized, res.code);
assert.eq(0, testDB.users.count());
diff --git a/jstests/auth/show_log_auth.js b/jstests/auth/show_log_auth.js
index bef5180ba9d..e28703aa1f1 100644
--- a/jstests/auth/show_log_auth.js
+++ b/jstests/auth/show_log_auth.js
@@ -21,8 +21,12 @@ finally {
print = oldprint;
}
-assert(printed[0]=='Error while trying to show logs: unauthorized');
-assert(printed[1]=='Error while trying to show ' + baseName + ' log: unauthorized');
+function assertStartsWith(s, prefix) {
+ assert.eq(s.substr(0, prefix.length), prefix);
+}
+
+assertStartsWith(printed[0], 'Error while trying to show logs');
+assertStartsWith(printed[1], 'Error while trying to show ' + baseName + ' log');
db.auth( "admin" , "pass" );
db.shutdownServer();
diff --git a/jstests/auth/system_user_privileges.js b/jstests/auth/system_user_privileges.js
index 6d397e70999..4bbabc77e2b 100644
--- a/jstests/auth/system_user_privileges.js
+++ b/jstests/auth/system_user_privileges.js
@@ -22,8 +22,7 @@
// Asserts that on the given "conn", "dbName"."collectionName".count() fails as unauthorized.
function assertCountUnauthorized(conn, dbName, collectionName) {
- assert.eq(runCountCommand(conn, dbName, collectionName).errmsg,
- "unauthorized",
+ assert.eq(runCountCommand(conn, dbName, collectionName).code, 13,
"On " + dbName + "." + collectionName);
}
diff --git a/jstests/sharding/auth.js b/jstests/sharding/auth.js
index 230e2429467..f9bcb881d36 100644
--- a/jstests/sharding/auth.js
+++ b/jstests/sharding/auth.js
@@ -80,7 +80,7 @@ logout(adminUser);
var result = s.getDB("admin").runCommand({addShard : shardName});
printjson(result);
-assert.eq(result.errmsg, "unauthorized");
+assert.eq(result.code, 13);
login(adminUser);
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index 493f8793644..3ededf1ec93 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -209,6 +209,14 @@ namespace mongo {
return client->getAuthorizationSession()->checkAuthForPrivileges(privileges);
}
+ void Command::appendCommandStatus(BSONObjBuilder& result, const Status& status) {
+ appendCommandStatus(result, status.isOK(), status.reason());
+ BSONObj tmp = result.asTempObj();
+ if (!status.isOK() && !tmp.hasField("code")) {
+ result.append("code", status.code());
+ }
+ }
+
void Command::logIfSlow( const Timer& timer, const string& msg ) {
int ms = timer.millis();
if ( ms > cmdLine.slowMS ) {
@@ -216,6 +224,47 @@ namespace mongo {
}
}
+ static Status _checkAuthorizationImpl(Command* c,
+ ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj,
+ bool fromRepl) {
+ if ( c->adminOnly() && ! fromRepl && dbname != "admin" ) {
+ return Status(ErrorCodes::Unauthorized, str::stream() << c->name <<
+ " may only be run against the admin database.");
+ }
+ if (AuthorizationManager::isAuthEnabled()) {
+ Status status = c->checkAuthForCommand(client, dbname, cmdObj);
+ if (status == ErrorCodes::Unauthorized) {
+ return Status(ErrorCodes::Unauthorized,
+ str::stream() << "not authorized on " << dbname <<
+ " to execute command " << cmdObj);
+ }
+ if (!status.isOK()) {
+ return status;
+ }
+ }
+ else if (c->adminOnly() &&
+ c->localHostOnlyIfNoAuth(cmdObj) &&
+ !client->getIsLocalHostConnection()) {
+
+ return Status(ErrorCodes::Unauthorized, str::stream() << c->name <<
+ " must run from localhost when running db without auth");
+ }
+ return Status::OK();
+ }
+
+ Status Command::_checkAuthorization(Command* c,
+ ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj,
+ bool fromRepl) {
+ Status status = _checkAuthorizationImpl(c, client, dbname, cmdObj, fromRepl);
+ if (!status.isOK()) {
+ log() << status << std::endl;
+ }
+ return status;
+ }
}
#include "../client/connpool.h"
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index 5f52aa97de7..edaa185e867 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -197,9 +197,29 @@ namespace mongo {
// Helper for setting errmsg and ok field in command result object.
static void appendCommandStatus(BSONObjBuilder& result, bool ok, const std::string& errmsg);
+ static void appendCommandStatus(BSONObjBuilder& result, const Status& status);
// Set by command line. Controls whether or not testing-only commands should be available.
static int testCommandsEnabled;
+
+ private:
+ /**
+ * Checks to see if the client is authorized to run the given command with the given
+ * parameters on the given named database.
+ *
+ * fromRepl is true if this command is running as part of oplog application, which for
+ * historic reasons has slightly different authorization semantics. TODO(schwerin): Check
+ * to see if this oddity can now be eliminated.
+ *
+ * Returns Status::OK() if the command is authorized. Most likely returns
+ * ErrorCodes::Unauthorized otherwise, but any return other than Status::OK implies not
+ * authorized.
+ */
+ static Status _checkAuthorization(Command* c,
+ ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj,
+ bool fromRepl);
};
bool _runCommands(const char *ns, BSONObj& jsobj, BufBuilder &b, BSONObjBuilder& anObjBuilder, bool fromRepl, int queryOptions);
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index 3a2a9036f62..8fa0c7d9442 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -2110,35 +2110,12 @@ namespace mongo {
std::string dbname = nsToDatabase( cmdns );
scoped_ptr<MaintenanceModeSetter> mmSetter;
- if (c->adminOnly() &&
- c->localHostOnlyIfNoAuth(cmdObj) &&
- !AuthorizationManager::isAuthEnabled() &&
- !client.getIsLocalHostConnection()) {
- log() << "command denied: " << cmdObj.toString() << endl;
- appendCommandStatus(result,
- false,
- "unauthorized: this command must run from localhost when running "
- "db without auth");
+ Status status = _checkAuthorization(c, &client, dbname, cmdObj, fromRepl);
+ if (!status.isOK()) {
+ appendCommandStatus(result, status);
return;
}
- if ( c->adminOnly() && ! fromRepl && dbname != "admin" ) {
- log() << "command denied: " << cmdObj.toString() << endl;
- appendCommandStatus(result, false, "access denied; use admin db");
- return;
- }
-
- if (AuthorizationManager::isAuthEnabled()) {
- Status status = c->checkAuthForCommand(&client, dbname, cmdObj);
- if (!status.isOK()) {
- log() << "command denied: " << cmdObj.toString() << endl;
- result.append("note", str::stream() << "not authorized for command: " <<
- c->name << " on database " << dbname);
- appendCommandStatus(result, false, status.reason());
- return;
- }
- }
-
if ( cmdObj["help"].trueValue() ) {
client.curop()->ensureStarted();
stringstream ss;
diff --git a/src/mongo/s/s_only.cpp b/src/mongo/s/s_only.cpp
index 48824ab7da3..ec71411b468 100644
--- a/src/mongo/s/s_only.cpp
+++ b/src/mongo/s/s_only.cpp
@@ -123,38 +123,13 @@ namespace mongo {
BSONObj& cmdObj,
BSONObjBuilder& result,
bool fromRepl ) {
- verify(c);
-
std::string dbname = nsToDatabase(ns);
- // Access control checks
- if (AuthorizationManager::isAuthEnabled()) {
- Status status = c->checkAuthForCommand(&client, dbname, cmdObj);
- if (!status.isOK()) {
- log() << "command denied: " << cmdObj.toString() << endl;
- result.append("note", str::stream() << "not authorized for command: " <<
- c->name << " on database " << dbname);
- appendCommandStatus(result, false, status.reason());
- return;
- }
- }
- if (c->adminOnly() &&
- c->localHostOnlyIfNoAuth(cmdObj) &&
- !AuthorizationManager::isAuthEnabled() &&
- !client.getIsLocalHostConnection()) {
- log() << "command denied: " << cmdObj.toString() << endl;
- appendCommandStatus(result,
- false,
- "unauthorized: this command must run from localhost when running db "
- "without auth");
- return;
- }
- if (c->adminOnly() && !startsWith(ns, "admin.")) {
- log() << "command denied: " << cmdObj.toString() << endl;
- appendCommandStatus(result, false, "access denied - use admin db");
+ Status status = _checkAuthorization(c, &client, dbname, cmdObj, fromRepl);
+ if (!status.isOK()) {
+ appendCommandStatus(result, status);
return;
}
- // End of access control checks
if (cmdObj.getBoolField("help")) {
stringstream help;