summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorSpencer T Brody <spencer@10gen.com>2012-11-27 15:44:13 -0500
committerSpencer T Brody <spencer@10gen.com>2012-12-07 11:38:54 -0500
commitfaf643fbbc9cf187c6b76d13ecd395d1eec04161 (patch)
treeb6ab3d9911793d039e498b5bb71f329d501aab9b /src/mongo
parent90440532fca3ce59383ad7e36437191f4819b3fc (diff)
downloadmongo-faf643fbbc9cf187c6b76d13ecd395d1eec04161.tar.gz
Check authorization in the new AuthorizationManager SERVER-7572
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/client/parallel.h2
-rw-r--r--src/mongo/db/auth/action_types.txt6
-rw-r--r--src/mongo/db/auth/auth_external_state_d.cpp6
-rw-r--r--src/mongo/db/auth/auth_external_state_d.h2
-rw-r--r--src/mongo/db/auth/auth_external_state_server_common.cpp5
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp121
-rw-r--r--src/mongo/db/auth/authorization_manager.h26
-rw-r--r--src/mongo/db/clientcursor.cpp43
-rw-r--r--src/mongo/db/clientcursor.h9
-rw-r--r--src/mongo/db/dbcommands.cpp16
-rw-r--r--src/mongo/db/index.cpp16
-rw-r--r--src/mongo/db/instance.cpp36
-rw-r--r--src/mongo/db/repl/heartbeat.cpp3
-rw-r--r--src/mongo/s/commands_public.cpp13
-rw-r--r--src/mongo/s/cursors.cpp9
-rw-r--r--src/mongo/s/cursors.h2
-rw-r--r--src/mongo/s/strategy.cpp19
-rw-r--r--src/mongo/s/strategy_shard.cpp43
-rw-r--r--src/mongo/s/strategy_single.cpp12
19 files changed, 345 insertions, 44 deletions
diff --git a/src/mongo/client/parallel.h b/src/mongo/client/parallel.h
index 23f248c71d2..cb7fdad6eaf 100644
--- a/src/mongo/client/parallel.h
+++ b/src/mongo/client/parallel.h
@@ -79,6 +79,8 @@ namespace mongo {
/** call before using */
void init();
+ virtual std::string getNS() { return _ns; }
+
virtual bool more() = 0;
virtual BSONObj next() = 0;
diff --git a/src/mongo/db/auth/action_types.txt b/src/mongo/db/auth/action_types.txt
index d48f5dbea6f..1b1ef965a45 100644
--- a/src/mongo/db/auth/action_types.txt
+++ b/src/mongo/db/auth/action_types.txt
@@ -37,7 +37,9 @@
"getShardVersion",
"handshake",
"hostInfo",
+"inprog",
"insert",
+"killop",
"listDatabases",
"listShards",
"logRotate",
@@ -45,7 +47,8 @@
"moveChunk",
"movePrimary",
"netstat",
-"profile",
+"profileEnable",
+"profileRead",
"reIndex",
"remove",
"removeShard",
@@ -73,6 +76,7 @@
"splitVector",
"top",
"touch",
+"unlock",
"unsetSharding",
"update",
"userAdmin",
diff --git a/src/mongo/db/auth/auth_external_state_d.cpp b/src/mongo/db/auth/auth_external_state_d.cpp
index ce15e4757ed..d6bfdfcb037 100644
--- a/src/mongo/db/auth/auth_external_state_d.cpp
+++ b/src/mongo/db/auth/auth_external_state_d.cpp
@@ -32,15 +32,21 @@ namespace mongo {
const string& principalName,
BSONObj* result) {
Client::GodScope gs;
+ Client::ReadContext(dbname + ".system.users");
DBDirectClient conn;
return getPrivilegeDocumentOverConnection(&conn, dbname, principalName, result);
}
bool AuthExternalStateMongod::hasPrivilegeDocument(const std::string& dbname) const {
Client::GodScope gs;
+ Client::ReadContext(dbname + ".system.users");
DBDirectClient conn;
BSONObj result = conn.findOne(dbname + ".system.users", Query());
return !result.isEmpty();
}
+ bool AuthExternalStateMongod::shouldIgnoreAuthChecks() const {
+ return cc().isGod() || AuthExternalStateServerCommon::shouldIgnoreAuthChecks();
+ }
+
} // namespace mongo
diff --git a/src/mongo/db/auth/auth_external_state_d.h b/src/mongo/db/auth/auth_external_state_d.h
index 5a54744278a..ac0adcc0bad 100644
--- a/src/mongo/db/auth/auth_external_state_d.h
+++ b/src/mongo/db/auth/auth_external_state_d.h
@@ -36,6 +36,8 @@ namespace mongo {
const string& principalName,
BSONObj* result);
+ virtual bool shouldIgnoreAuthChecks() const;
+
protected:
virtual bool hasPrivilegeDocument(const std::string& dbname) const;
};
diff --git a/src/mongo/db/auth/auth_external_state_server_common.cpp b/src/mongo/db/auth/auth_external_state_server_common.cpp
index 55e67f601d5..e5117b4ac7e 100644
--- a/src/mongo/db/auth/auth_external_state_server_common.cpp
+++ b/src/mongo/db/auth/auth_external_state_server_common.cpp
@@ -37,8 +37,9 @@ namespace mongo {
}
bool AuthExternalStateServerCommon::shouldIgnoreAuthChecks() const {
-
- return noauth || cc().isGod() || (cc().getIsLocalHostConnection() && _allowLocalhost());
+ // TODO: cache if admin user exists and if it once existed don't query admin.system.users
+ ClientBasic* client = ClientBasic::getCurrent();
+ return noauth || (client->getIsLocalHostConnection() && _allowLocalhost());
}
} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp
index 77794801bb0..8b18e6a70f9 100644
--- a/src/mongo/db/auth/authorization_manager.cpp
+++ b/src/mongo/db/auth/authorization_manager.cpp
@@ -17,6 +17,7 @@
#include "mongo/db/auth/authorization_manager.h"
#include <string>
+#include <vector>
#include "mongo/base/init.h"
#include "mongo/base/status.h"
@@ -98,6 +99,8 @@ namespace mongo {
dbAdminRoleActions.addAction(ActionType::convertToCapped);
dbAdminRoleActions.addAction(ActionType::dbStats);
dbAdminRoleActions.addAction(ActionType::dropCollection);
+ dbAdminRoleActions.addAction(ActionType::profileEnable);
+ dbAdminRoleActions.addAction(ActionType::profileRead);
dbAdminRoleActions.addAction(ActionType::reIndex); // TODO: Should readWrite have this also? This isn't consistent with ENSURE_INDEX and DROP_INDEXES
dbAdminRoleActions.addAction(ActionType::renameCollection);
dbAdminRoleActions.addAction(ActionType::validate);
@@ -117,9 +120,10 @@ namespace mongo {
serverAdminRoleActions.addAction(ActionType::getShardMap);
serverAdminRoleActions.addAction(ActionType::getShardVersion);
serverAdminRoleActions.addAction(ActionType::hostInfo);
+ serverAdminRoleActions.addAction(ActionType::inprog);
+ serverAdminRoleActions.addAction(ActionType::killop);
serverAdminRoleActions.addAction(ActionType::listDatabases);
serverAdminRoleActions.addAction(ActionType::logRotate);
- serverAdminRoleActions.addAction(ActionType::profile); // TODO: should this be dbAdmin?
serverAdminRoleActions.addAction(ActionType::repairDatabase);
serverAdminRoleActions.addAction(ActionType::replSetFreeze);
serverAdminRoleActions.addAction(ActionType::replSetGetStatus);
@@ -133,6 +137,7 @@ namespace mongo {
serverAdminRoleActions.addAction(ActionType::shutdown);
serverAdminRoleActions.addAction(ActionType::top);
serverAdminRoleActions.addAction(ActionType::touch);
+ serverAdminRoleActions.addAction(ActionType::unlock);
// Cluster admin role
clusterAdminRoleActions.addAction(ActionType::addShard);
@@ -351,4 +356,118 @@ namespace mongo {
return NULL; // Not authorized
}
+ Status AuthorizationManager::checkAuthForQuery(const std::string& ns) {
+ NamespaceString namespaceString(ns);
+ verify(!namespaceString.isCommand());
+ if (namespaceString.coll == "system.users") {
+ if (!checkAuthorization(ns, ActionType::userAdmin)) {
+ return Status(ErrorCodes::Unauthorized,
+ mongoutils::str::stream() <<
+ "unauthorized to read user information for database " <<
+ namespaceString.db,
+ 0);
+ }
+ }
+ else if (namespaceString.coll == "system.profile") {
+ if (!checkAuthorization(ns, ActionType::profileRead)) {
+ return Status(ErrorCodes::Unauthorized,
+ mongoutils::str::stream() << "unauthorized to read " <<
+ namespaceString.db << ".system.profile",
+ 0);
+ }
+ }
+ else {
+ if (!checkAuthorization(ns, ActionType::find)) {
+ return Status(ErrorCodes::Unauthorized,
+ mongoutils::str::stream() << "unauthorized for query on " << ns,
+ 0);
+ }
+ }
+ return Status::OK();
+ }
+
+ Status AuthorizationManager::checkAuthForInsert(const std::string& ns) {
+ NamespaceString namespaceString(ns);
+ if (namespaceString.coll == "system.users") {
+ if (!checkAuthorization(ns, ActionType::userAdmin)) {
+ return Status(ErrorCodes::Unauthorized,
+ mongoutils::str::stream() <<
+ "unauthorized to create user for database " <<
+ namespaceString.db,
+ 0);
+ }
+ }
+ else {
+ if (!checkAuthorization(ns, ActionType::insert)) {
+ return Status(ErrorCodes::Unauthorized,
+ mongoutils::str::stream() << "unauthorized for insert on " << ns,
+ 0);
+ }
+ }
+ return Status::OK();
+ }
+
+ Status AuthorizationManager::checkAuthForUpdate(const std::string& ns, bool upsert) {
+ NamespaceString namespaceString(ns);
+ if (namespaceString.coll == "system.users") {
+ if (!checkAuthorization(ns, ActionType::userAdmin)) {
+ return Status(ErrorCodes::Unauthorized,
+ mongoutils::str::stream() <<
+ "not authorized to update user information for database " <<
+ namespaceString.db,
+ 0);
+ }
+ }
+ else {
+ if (!checkAuthorization(ns, ActionType::update)) {
+ return Status(ErrorCodes::Unauthorized,
+ mongoutils::str::stream() << "not authorized for update on " << ns,
+ 0);
+ }
+ if (upsert && !checkAuthorization(ns, ActionType::insert)) {
+ return Status(ErrorCodes::Unauthorized,
+ mongoutils::str::stream() << "not authorized for upsert on " << ns,
+ 0);
+ }
+ }
+ return Status::OK();
+ }
+
+ Status AuthorizationManager::checkAuthForDelete(const std::string& ns) {
+ NamespaceString namespaceString(ns);
+ if (namespaceString.coll == "system.users") {
+ if (!checkAuthorization(ns, ActionType::userAdmin)) {
+ return Status(ErrorCodes::Unauthorized,
+ mongoutils::str::stream() <<
+ "not authorized to remove user from database " <<
+ namespaceString.db,
+ 0);
+ }
+ }
+ else {
+ if (!checkAuthorization(ns, ActionType::remove)) {
+ return Status(ErrorCodes::Unauthorized,
+ mongoutils::str::stream() << "not authorized to remove from " << ns,
+ 0);
+ }
+ }
+ return Status::OK();
+ }
+
+ Status AuthorizationManager::checkAuthForGetMore(const std::string& ns) {
+ return checkAuthForQuery(ns);
+ }
+
+ Status AuthorizationManager::checkAuthForPrivileges(const vector<Privilege>& privileges) {
+ for (std::vector<Privilege>::const_iterator it = privileges.begin();
+ it != privileges.end(); ++it) {
+ const Privilege& privilege = *it;
+ ActionSet actions = privilege.getActions();
+ if (!checkAuthorization(privilege.getResource(), privilege.getActions())) {
+ return Status(ErrorCodes::Unauthorized, "unauthorized", 0);
+ }
+ }
+ return Status::OK();
+ }
+
} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h
index 8eae9a1cf9c..865205f1b79 100644
--- a/src/mongo/db/auth/authorization_manager.h
+++ b/src/mongo/db/auth/authorization_manager.h
@@ -17,6 +17,7 @@
#pragma once
#include <string>
+#include <vector>
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
@@ -103,11 +104,34 @@ namespace mongo {
return _externalState->getPrivilegeDocument(dbname, userName, result);
}
+ // Checks if this connection has the privileges necessary to perform a query on the given
+ // namespace.
+ Status checkAuthForQuery(const std::string& ns);
+
+ // Checks if this connection has the privileges necessary to perform an update on the given
+ // namespace.
+ Status checkAuthForUpdate(const std::string& ns, bool upsert);
+
+ // Checks if this connection has the privileges necessary to perform an insert to the given
+ // namespace.
+ Status checkAuthForInsert(const std::string& ns);
+
+ // Checks if this connection has the privileges necessary to perform a delete on the given
+ // namespace.
+ Status checkAuthForDelete(const std::string& ns);
+
+ // Checks if this connection has the privileges necessary to perform a getMore on the given
+ // namespace.
+ Status checkAuthForGetMore(const std::string& ns);
+
+ // Checks if this connection is authorized for all the given Privileges
+ Status checkAuthForPrivileges(const vector<Privilege>& privileges);
+
// Given a database name and a readOnly flag return an ActionSet describing all the actions
// that an old-style user with those attributes should be given.
static ActionSet getActionsForOldStyleUser(const std::string& dbname, bool readOnly);
- // Parses the privilege document and returns a PrivilegeSet of all the Capabilities that
+ // Parses the privilege document and returns a PrivilegeSet of all the Privileges that
// the privilege document grants.
static Status buildPrivilegeSet(const std::string& dbname,
Principal* principal,
diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp
index e1e9ee5705d..562985023ec 100644
--- a/src/mongo/db/clientcursor.cpp
+++ b/src/mongo/db/clientcursor.cpp
@@ -847,35 +847,60 @@ namespace mongo {
}
}
- bool ClientCursor::erase( CursorId id ) {
- recursive_scoped_lock lock( ccmutex );
- ClientCursor *cursor = find_inlock( id );
+ bool ClientCursor::_erase_inlock(ClientCursor* cursor) {
if ( ! cursor )
return false;
- if ( ! cc().getAuthenticationInfo()->isAuthorizedReads( nsToDatabase( cursor->ns() ) ) )
- return false;
-
// Must not have an active ClientCursor::Pin.
massert( 16089,
- str::stream() << "Cannot kill active cursor " << id,
+ str::stream() << "Cannot kill active cursor " << cursor->cursorid(),
cursor->_pinValue < 100 );
-
+
delete cursor;
return true;
}
+ bool ClientCursor::erase(CursorId id) {
+ recursive_scoped_lock lock(ccmutex);
+ ClientCursor* cursor = find_inlock(id);
+ return _erase_inlock(cursor);
+ }
+
+ bool ClientCursor::eraseIfAuthorized(CursorId id) {
+ recursive_scoped_lock lock(ccmutex);
+ ClientCursor* cursor = find_inlock(id);
+
+ if (!cc().getAuthorizationManager()->checkAuthorization(cursor->ns(),
+ ActionType::find)
+ || !cc().getAuthenticationInfo()->isAuthorizedReads(nsToDatabase(cursor->ns()))) {
+ return false;
+ }
+
+ return _erase_inlock(cursor);
+ }
+
int ClientCursor::erase(int n, long long *ids) {
int found = 0;
for ( int i = 0; i < n; i++ ) {
- if ( erase(ids[i]) )
+ if ( erase(ids[i]))
found++;
if ( inShutdown() )
break;
}
return found;
+ }
+ int ClientCursor::eraseIfAuthorized(int n, long long *ids) {
+ int found = 0;
+ for ( int i = 0; i < n; i++ ) {
+ if ( eraseIfAuthorized(ids[i]))
+ found++;
+
+ if ( inShutdown() )
+ break;
+ }
+ return found;
}
ClientCursor::YieldLock::YieldLock( ptr<ClientCursor> cc )
diff --git a/src/mongo/db/clientcursor.h b/src/mongo/db/clientcursor.h
index 4c1373d5956..c50bbd81a37 100644
--- a/src/mongo/db/clientcursor.h
+++ b/src/mongo/db/clientcursor.h
@@ -324,13 +324,19 @@ namespace mongo {
/**
* Deletes the cursor with the provided @param 'id' if one exists.
* @throw if the cursor with the provided id is pinned.
+ * This does not do any auth checking and should be used only when erasing cursors as part
+ * of cleaning up internal operations.
*/
static bool erase(CursorId id);
+ // Same as erase but checks to make sure this thread has read permission on the cursor's
+ // namespace. This should be called when receiving killCursors from a client.
+ static bool eraseIfAuthorized(CursorId id);
/**
* @return number of cursors found
*/
- static int erase( int n , long long * ids );
+ static int erase(int n, long long* ids);
+ static int eraseIfAuthorized(int n, long long* ids);
void mayUpgradeStorage() {
/* if ( !ids_.get() )
@@ -377,6 +383,7 @@ namespace mongo {
CCByLoc& byLoc() { return _db->ccByLoc; }
Record* _recordForYield( RecordNeeds need );
+ static bool _erase_inlock(ClientCursor* cursor);
private:
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index 8f962b27325..34bc10a57ef 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -484,9 +484,8 @@ namespace mongo {
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
ActionSet actions;
- actions.addAction(ActionType::profile);
- // TODO: should the resource here be the database instead of server?
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ actions.addAction(ActionType::profileEnable);
+ out->push_back(Privilege(dbname, actions));
}
CmdProfile() : Command("profile") {}
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
@@ -1931,6 +1930,17 @@ namespace mongo {
return false;
}
+ if (c->requiresAuth()) {
+ std::vector<Privilege> privileges;
+ c->addRequiredPrivileges(dbname, cmdObj, &privileges);
+ Status status = client.getAuthorizationManager()->checkAuthForPrivileges(privileges);
+ if (!status.isOK()) {
+ result.append("errmsg", status.reason());
+ log() << "command denied: " << cmdObj.toString() << endl;
+ return false;
+ }
+ }
+
if ( cmdObj["help"].trueValue() ) {
client.curop()->ensureStarted();
stringstream ss;
diff --git a/src/mongo/db/index.cpp b/src/mongo/db/index.cpp
index 1925d2e5773..95f4575cdf4 100644
--- a/src/mongo/db/index.cpp
+++ b/src/mongo/db/index.cpp
@@ -22,6 +22,8 @@
#include <boost/checked_delete.hpp>
+#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/background.h"
#include "mongo/db/btree.h"
#include "mongo/db/index_update.h"
@@ -29,6 +31,7 @@
#include "mongo/db/ops/delete.h"
#include "mongo/db/repl/rs.h"
#include "mongo/util/scopeguard.h"
+#include "mongo/util/mongoutils/str.h"
namespace mongo {
@@ -292,16 +295,21 @@ namespace mongo {
BSONObj& fixedIndexObject) {
sourceCollection = 0;
- // logical name of the index. todo: get rid of the name, we don't need it!
- const char *name = io.getStringField("name");
- uassert(12523, "no index name specified", *name);
-
// the collection for which we are building an index
sourceNS = io.getStringField("ns");
uassert(10096, "invalid ns to index", sourceNS.find( '.' ) != string::npos);
massert(10097, str::stream() << "bad table to index name on add index attempt current db: " << cc().database()->name << " source: " << sourceNS ,
cc().database()->name == nsToDatabase(sourceNS.c_str()));
+ uassert(16548,
+ mongoutils::str::stream() << "not authorized to create index on " << sourceNS,
+ cc().getAuthorizationManager()->checkAuthorization(sourceNS,
+ ActionType::ensureIndex));
+
+ // logical name of the index. todo: get rid of the name, we don't need it!
+ const char *name = io.getStringField("name");
+ uassert(12523, "no index name specified", *name);
+
BSONObj key = io.getObjectField("key");
uassert(12524, "index key pattern too large", key.objsize() <= 2048);
if( !validKeyPattern(key) ) {
diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp
index 0e84e57e019..176a380ff26 100644
--- a/src/mongo/db/instance.cpp
+++ b/src/mongo/db/instance.cpp
@@ -28,7 +28,10 @@
#endif
#include "mongo/util/time_support.h"
+#include "mongo/base/status.h"
#include "mongo/bson/util/atomic_int.h"
+#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/background.h"
#include "mongo/db/cmdline.h"
#include "mongo/db/commands/fsync.h"
@@ -43,6 +46,7 @@
#include "mongo/db/json.h"
#include "mongo/db/kill_current_op.h"
#include "mongo/db/lasterror.h"
+#include "mongo/db/namespacestring.h"
#include "mongo/db/ops/count.h"
#include "mongo/db/ops/delete.h"
#include "mongo/db/ops/query.h"
@@ -55,6 +59,7 @@
#include "mongo/s/d_logic.h"
#include "mongo/util/file_allocator.h"
#include "mongo/util/goodies.h"
+#include "mongo/util/mongoutils/str.h"
namespace mongo {
@@ -148,7 +153,8 @@ namespace mongo {
void inProgCmd( Message &m, DbResponse &dbresponse ) {
BSONObjBuilder b;
- if( ! cc().isAdmin() ) {
+ if (!cc().isAdmin() || !cc().getAuthorizationManager()->checkAuthorization(
+ AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::inprog)) {
b.append("err", "unauthorized");
}
else {
@@ -188,7 +194,8 @@ namespace mongo {
void killOp( Message &m, DbResponse &dbresponse ) {
BSONObj obj;
- if( ! cc().isAdmin() ) {
+ if (!cc().isAdmin() || !cc().getAuthorizationManager()->checkAuthorization(
+ AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::killop)) {
obj = fromjson("{\"err\":\"unauthorized\"}");
}
/*else if( !dbMutexInfo.isLocked() )
@@ -213,7 +220,8 @@ namespace mongo {
bool _unlockFsync();
void unlockFsync(const char *ns, Message& m, DbResponse &dbresponse) {
BSONObj obj;
- if ( ! cc().isAdmin() ) { // checks auth
+ if (!cc().isAdmin() || !cc().getAuthorizationManager()->checkAuthorization(
+ AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::unlock)) {
obj = fromjson("{\"err\":\"unauthorized\"}");
}
else if (strncmp(ns, "admin.", 6) != 0 ) {
@@ -244,6 +252,11 @@ namespace mongo {
shared_ptr<AssertionException> ex;
try {
+ if (!NamespaceString(d.getns()).isCommand()) {
+ // Auth checking for Commands happens later.
+ Status status = cc().getAuthorizationManager()->checkAuthForQuery(d.getns());
+ uassert(16550, status.reason(), status.isOK());
+ }
dbresponse.exhaustNS = runQuery(m, q, op, *resp);
verify( !resp->empty() );
}
@@ -500,7 +513,7 @@ namespace mongo {
verify( n < 30000 );
}
- int found = ClientCursor::erase(n, (long long *) x);
+ int found = ClientCursor::eraseIfAuthorized(n, (long long *) x);
if ( logLevel > 0 || found != n ) {
LOG( found == n ? 1 : 0 ) << "killcursors: found " << found << " of " << n << endl;
@@ -554,7 +567,10 @@ namespace mongo {
bool upsert = flags & UpdateOption_Upsert;
bool multi = flags & UpdateOption_Multi;
bool broadcast = flags & UpdateOption_Broadcast;
-
+
+ Status status = cc().getAuthorizationManager()->checkAuthForUpdate(ns, upsert);
+ uassert(16538, status.reason(), status.isOK());
+
op.debug().query = query;
op.setQuery(query);
@@ -586,6 +602,10 @@ namespace mongo {
void receivedDelete(Message& m, CurOp& op) {
DbMessage d(m);
const char *ns = d.getns();
+
+ Status status = cc().getAuthorizationManager()->checkAuthForDelete(ns);
+ uassert(16542, status.reason(), status.isOK());
+
op.debug().ns = ns;
int flags = d.pullInt();
bool justOne = flags & RemoveOption_JustOne;
@@ -655,6 +675,9 @@ namespace mongo {
const NamespaceString nsString( ns );
uassert( 16258, str::stream() << "Invalid ns [" << ns << "]", nsString.isValid() );
+ Status status = cc().getAuthorizationManager()->checkAuthForGetMore(ns);
+ uassert(16543, status.reason(), status.isOK());
+
if (str::startsWith(ns, "local.oplog.")){
if (pass == 0) {
mutex::scoped_lock lk(OpTime::m);
@@ -784,6 +807,9 @@ namespace mongo {
const char *ns = d.getns();
op.debug().ns = ns;
+ Status status = cc().getAuthorizationManager()->checkAuthForInsert(ns);
+ uassert(16544, status.reason(), status.isOK());
+
if( !d.moreJSObjs() ) {
// strange. should we complain?
return;
diff --git a/src/mongo/db/repl/heartbeat.cpp b/src/mongo/db/repl/heartbeat.cpp
index 34663ff7cb3..589d51a9ba2 100644
--- a/src/mongo/db/repl/heartbeat.cpp
+++ b/src/mongo/db/repl/heartbeat.cpp
@@ -245,8 +245,7 @@ namespace mongo {
if( ok ) {
up(info, mem);
}
- else if (!info["errmsg"].eoo() &&
- info["errmsg"].str() == "need to login") {
+ else if (!info["errmsg"].eoo() && info["errmsg"].str() == "unauthorized") {
authIssue(mem);
}
else {
diff --git a/src/mongo/s/commands_public.cpp b/src/mongo/s/commands_public.cpp
index 08604cfd1ff..53a8272fc12 100644
--- a/src/mongo/s/commands_public.cpp
+++ b/src/mongo/s/commands_public.cpp
@@ -263,8 +263,8 @@ namespace mongo {
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
ActionSet actions;
- actions.addAction(ActionType::profile);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ actions.addAction(ActionType::profileEnable);
+ out->push_back(Privilege(dbname, actions));
}
} profileCmd;
@@ -1844,10 +1844,15 @@ namespace mongo {
char cl[256];
nsToDatabase(ns, cl);
- if( c->requiresAuth() && !ai->isAuthorizedForLock(cl, c->locktype())) {
+ std::vector<Privilege> privileges;
+ c->addRequiredPrivileges(cl, jsobj, &privileges);
+ if (c->requiresAuth() &&
+ (!client->getAuthorizationManager()->checkAuthForPrivileges(privileges).isOK()
+ || !ai->isAuthorizedForLock(cl, c->locktype()))) {
ok = false;
errmsg = "unauthorized";
- anObjBuilder.append( "note" , str::stream() << "need to authorized on db: " << cl << " for command: " << e.fieldName() );
+ anObjBuilder.append("note", str::stream() << "unauthorized for command: " <<
+ e.fieldName() << " on database " << cl);
}
else if( c->adminOnly() && c->localHostOnlyIfNoAuth( jsobj ) && noauth && !ai->isLocalHost() ) {
ok = false;
diff --git a/src/mongo/s/cursors.cpp b/src/mongo/s/cursors.cpp
index 77a495e2efc..acdbc1a5b67 100644
--- a/src/mongo/s/cursors.cpp
+++ b/src/mongo/s/cursors.cpp
@@ -276,6 +276,8 @@ namespace mongo {
uassert( 13287 , "too many cursors to kill" , n < 30000 );
long long * cursors = (long long *)x;
+ AuthorizationManager* authManager =
+ ClientBasic::getCurrent()->getAuthorizationManager();
for ( int i=0; i<n; i++ ) {
long long id = cursors[i];
LOG(_myLogLevel) << "CursorCache::gotKillCursors id: " << id << endl;
@@ -291,7 +293,9 @@ namespace mongo {
MapSharded::iterator i = _cursors.find( id );
if ( i != _cursors.end() ) {
- _cursors.erase( i );
+ if (authManager->checkAuthorization(i->second->getNS(), ActionType::find)) {
+ _cursors.erase( i );
+ }
continue;
}
@@ -302,6 +306,9 @@ namespace mongo {
continue;
}
verify(refsNSIt != _refsNS.end());
+ if (!authManager->checkAuthorization(refsNSIt->second, ActionType::find)) {
+ continue;
+ }
server = refsIt->second;
_refs.erase(refsIt);
_refsNS.erase(refsNSIt);
diff --git a/src/mongo/s/cursors.h b/src/mongo/s/cursors.h
index 8666d2d5497..b42ea7538d7 100644
--- a/src/mongo/s/cursors.h
+++ b/src/mongo/s/cursors.h
@@ -67,6 +67,8 @@ namespace mongo {
/** @return idle time in ms */
long long idleTime( long long now );
+ std::string getNS() { return _cursor->getNS(); }
+
// The default initial buffer size for sending responses.
static const int INIT_REPLY_BUFFER_SIZE;
diff --git a/src/mongo/s/strategy.cpp b/src/mongo/s/strategy.cpp
index 7ce25991e5f..6964b2c4fd2 100644
--- a/src/mongo/s/strategy.cpp
+++ b/src/mongo/s/strategy.cpp
@@ -18,15 +18,18 @@
#include "pch.h"
-#include "../client/connpool.h"
-#include "../db/commands.h"
+#include "mongo/s/strategy.h"
+
+#include "mongo/client/connpool.h"
+#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/commands.h"
+#include "mongo/s/grid.h"
+#include "mongo/s/request.h"
+#include "mongo/s/server.h"
+#include "mongo/s/writeback_listener.h"
+#include "mongo/util/mongoutils/str.h"
-#include "grid.h"
-#include "request.h"
-#include "server.h"
-#include "writeback_listener.h"
-
-#include "strategy.h"
namespace mongo {
diff --git a/src/mongo/s/strategy_shard.cpp b/src/mongo/s/strategy_shard.cpp
index 09caa5c77f0..6d50fc669b2 100644
--- a/src/mongo/s/strategy_shard.cpp
+++ b/src/mongo/s/strategy_shard.cpp
@@ -18,17 +18,22 @@
#include "pch.h"
+#include "mongo/base/status.h"
#include "mongo/bson/util/builder.h"
#include "mongo/client/connpool.h"
#include "mongo/client/dbclientcursor.h"
+#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/commands.h"
#include "mongo/db/index.h"
+#include "mongo/db/namespacestring.h"
#include "mongo/s/client_info.h"
#include "mongo/s/chunk.h"
#include "mongo/s/cursors.h"
#include "mongo/s/grid.h"
#include "mongo/s/request.h"
#include "mongo/s/stats.h"
+#include "mongo/util/mongoutils/str.h"
// error codes 8010-8040
@@ -46,6 +51,11 @@ namespace mongo {
QueryMessage q( r.d() );
+ AuthorizationManager* authManager =
+ ClientBasic::getCurrent()->getAuthorizationManager();
+ Status status = authManager->checkAuthForQuery(q.ns);
+ uassert(16549, status.reason(), status.isOK());
+
r.checkAuth( Auth::READ );
LOG(3) << "shard query: " << q.ns << " " << q.query << endl;
@@ -165,6 +175,13 @@ namespace mongo {
virtual void getMore( Request& r ) {
+ const char *ns = r.getns();
+
+ AuthorizationManager* authManager =
+ ClientBasic::getCurrent()->getAuthorizationManager();
+ Status status = authManager->checkAuthForGetMore(ns);
+ uassert(16539, status.reason(), status.isOK());
+
// TODO: Handle stale config exceptions here from coll being dropped or sharded during op
// for now has same semantics as legacy request
ChunkManagerPtr info = r.getChunkManager();
@@ -175,8 +192,6 @@ namespace mongo {
if( ! info ){
- const char *ns = r.getns();
-
LOG(3) << "single getmore: " << ns << endl;
long long id = r.d().getInt64( 4 );
@@ -499,6 +514,12 @@ namespace mongo {
const string& ns = r.getns();
+ AuthorizationManager* authManager =
+ ClientBasic::getCurrent()->getAuthorizationManager();
+ Status status = authManager->checkAuthForInsert(ns);
+ uassert(16540, status.reason(), status.isOK());
+
+
int flags = 0;
if (d.reservedField() & Reserved_InsertOption_ContinueOnError) flags |=
@@ -985,6 +1006,12 @@ namespace mongo {
int flags = d.pullInt();
const BSONObj query = d.nextJsObj();
+ bool upsert = flags & UpdateOption_Upsert;
+ AuthorizationManager* authManager =
+ ClientBasic::getCurrent()->getAuthorizationManager();
+ Status status = authManager->checkAuthForUpdate(ns, upsert);
+ uassert(16537, status.reason(), status.isOK());
+
uassert( 10201 , "invalid update" , d.moreJSObjs() );
const BSONObj toUpdate = d.nextJsObj();
@@ -1141,6 +1168,11 @@ namespace mongo {
const string& ns = r.getns();
int flags = d.pullInt();
+ AuthorizationManager* authManager =
+ ClientBasic::getCurrent()->getAuthorizationManager();
+ Status status = authManager->checkAuthForDelete(ns);
+ uassert(16541, status.reason(), status.isOK());
+
uassert( 10203 , "bad delete message" , d.moreJSObjs() );
const BSONObj query = d.nextJsObj();
@@ -1246,6 +1278,13 @@ namespace mongo {
while( d.moreJSObjs() ) {
BSONObj o = d.nextJsObj();
const char * ns = o["ns"].valuestr();
+
+ AuthorizationManager* authManager =
+ ClientBasic::getCurrent()->getAuthorizationManager();
+ uassert(16547,
+ mongoutils::str::stream() << "not authorized to create index on " << ns,
+ authManager->checkAuthorization(ns, ActionType::ensureIndex));
+
if ( r.getConfig()->isSharded( ns ) ) {
BSONObj newIndexKey = o["key"].embeddedObjectUserCheck();
diff --git a/src/mongo/s/strategy_single.cpp b/src/mongo/s/strategy_single.cpp
index 4fca33f76da..fe91e66e135 100644
--- a/src/mongo/s/strategy_single.cpp
+++ b/src/mongo/s/strategy_single.cpp
@@ -133,7 +133,15 @@ namespace mongo {
BSONObjBuilder b;
vector<Shard> shards;
+ AuthorizationManager* authManager =
+ ClientBasic::getCurrent()->getAuthorizationManager();
+
if ( strcmp( ns , "inprog" ) == 0 ) {
+ uassert(16545,
+ "not authorized to run inprog",
+ authManager->checkAuthorization(AuthorizationManager::SERVER_RESOURCE_NAME,
+ ActionType::inprog));
+
Shard::getAllShards( shards );
BSONArrayBuilder arr( b.subarrayStart( "inprog" ) );
@@ -172,6 +180,10 @@ namespace mongo {
arr.done();
}
else if ( strcmp( ns , "killop" ) == 0 ) {
+ uassert(16546,
+ "not authorized to run killop",
+ authManager->checkAuthorization(AuthorizationManager::SERVER_RESOURCE_NAME,
+ ActionType::killop));
r.checkAuth( Auth::WRITE , "admin" );
BSONElement e = q.query["op"];