summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorAmalia Hawkins <amalia.hawkins@10gen.com>2014-04-21 18:43:25 -0400
committerAmalia Hawkins <amalia.hawkins@10gen.com>2014-05-22 20:29:39 -0400
commit1b4b52a9d413e145478a303b63ab760894938c80 (patch)
tree3286cdd06d688d4345a80215f84b4674a398b753 /src/mongo/db
parent7a85cae38fba537980d6c9fc573ef077fd2df74e (diff)
downloadmongo-1b4b52a9d413e145478a303b63ab760894938c80.tar.gz
SERVER-12621 narrow the localhost exception when auth is enabled
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/auth/authorization_session.cpp52
-rw-r--r--src/mongo/db/auth/authorization_session.h7
-rw-r--r--src/mongo/db/auth/authz_session_external_state.h12
-rw-r--r--src/mongo/db/auth/authz_session_external_state_mock.h18
-rw-r--r--src/mongo/db/auth/authz_session_external_state_server_common.cpp11
-rw-r--r--src/mongo/db/auth/authz_session_external_state_server_common.h1
-rw-r--r--src/mongo/db/commands/authentication_commands.cpp8
7 files changed, 97 insertions, 12 deletions
diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp
index 6c932ab6375..a934ee3aae6 100644
--- a/src/mongo/db/auth/authorization_session.cpp
+++ b/src/mongo/db/auth/authorization_session.cpp
@@ -124,6 +124,42 @@ namespace {
_authenticatedUsers.add(internalSecurity.user);
}
+ PrivilegeVector AuthorizationSession::getDefaultPrivileges() {
+ PrivilegeVector defaultPrivileges;
+
+ // If localhost exception is active (and no users exist),
+ // return a vector of the minimum privileges required to bootstrap
+ // a system and add the first user.
+ if (_externalState->shouldAllowLocalhost()) {
+ ResourcePattern adminDBResource = ResourcePattern::forDatabaseName(ADMIN_DBNAME);
+ ActionSet setupAdminUserActionSet;
+ setupAdminUserActionSet.addAction(ActionType::createUser);
+ setupAdminUserActionSet.addAction(ActionType::grantRole);
+ Privilege setupAdminUserPrivilege =
+ Privilege(adminDBResource, setupAdminUserActionSet);
+
+ ResourcePattern externalDBResource = ResourcePattern::forDatabaseName("$external");
+ Privilege setupExternalUserPrivilege =
+ Privilege(externalDBResource, ActionType::createUser);
+
+ ActionSet setupServerConfigActionSet;
+ setupServerConfigActionSet.addAction(ActionType::addShard);
+ setupServerConfigActionSet.addAction(ActionType::replSetConfigure);
+ setupServerConfigActionSet.addAction(ActionType::replSetGetStatus);
+ Privilege setupServerConfigPrivilege =
+ Privilege(ResourcePattern::forClusterResource(), setupServerConfigActionSet);
+
+ Privilege::addPrivilegeToPrivilegeVector(&defaultPrivileges, setupAdminUserPrivilege);
+ Privilege::addPrivilegeToPrivilegeVector(&defaultPrivileges,
+ setupExternalUserPrivilege);
+ Privilege::addPrivilegeToPrivilegeVector(&defaultPrivileges,
+ setupServerConfigPrivilege);
+ return defaultPrivileges;
+ }
+
+ return defaultPrivileges;
+ }
+
Status AuthorizationSession::checkAuthForQuery(const NamespaceString& ns,
const BSONObj& query) {
if (MONGO_unlikely(ns.isCommand())) {
@@ -435,6 +471,22 @@ namespace {
ActionSet unmetRequirements = privilege.getActions();
+ PrivilegeVector defaultPrivileges = getDefaultPrivileges();
+ for (PrivilegeVector::iterator it = defaultPrivileges.begin();
+ it != defaultPrivileges.end(); ++it) {
+
+ for (int i = 0; i < resourceSearchListLength; ++i) {
+ if (!(it->getResourcePattern() == resourceSearchList[i]))
+ continue;
+
+ ActionSet userActions = it->getActions();
+ unmetRequirements.removeAllActionsFromSet(userActions);
+
+ if (unmetRequirements.empty())
+ return true;
+ }
+ }
+
for (UserSet::iterator it = _authenticatedUsers.begin();
it != _authenticatedUsers.end(); ++it) {
User* user = *it;
diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h
index 92e4e6f6552..1a12a0719e0 100644
--- a/src/mongo/db/auth/authorization_session.h
+++ b/src/mongo/db/auth/authorization_session.h
@@ -100,6 +100,13 @@ namespace mongo {
// Used to grant internal threads full access.
void grantInternalAuthorization();
+ // Generates a vector of default privileges that are granted to any user,
+ // regardless of which roles that user does or does not possess.
+ // If localhost exception is active, the permissions include the ability to create
+ // the first user and the ability to run the commands needed to bootstrap the system
+ // into a state where the first user can be created.
+ PrivilegeVector getDefaultPrivileges();
+
// Checks if this connection has the privileges necessary to perform the given query on the
// given namespace.
Status checkAuthForQuery(const NamespaceString& ns, const BSONObj& query);
diff --git a/src/mongo/db/auth/authz_session_external_state.h b/src/mongo/db/auth/authz_session_external_state.h
index 2f8b4d097c5..dbd838cb68f 100644
--- a/src/mongo/db/auth/authz_session_external_state.h
+++ b/src/mongo/db/auth/authz_session_external_state.h
@@ -56,12 +56,16 @@ namespace mongo {
// Returns true if this connection should be treated as if it has full access to do
// anything, regardless of the current auth state. Currently the reasons why this could be
- // are that auth isn't enabled, the connection is from localhost and there are no admin
- // users, or the connection is a "god" connection.
- // NOTE: _checkShouldAllowLocalhost MUST be called at least once before any call to
- // shouldIgnoreAuthChecks or we could ignore auth checks incorrectly.
+ // are that auth isn't enabled or the connection is a "god" connection.
virtual bool shouldIgnoreAuthChecks() const = 0;
+ // Returns true if this connection should be treated as a localhost connection with no
+ // admin authentication users created. This condition is used to allow the creation of
+ // the first user on a server with authorization enabled.
+ // NOTE: _checkShouldAllowLocalhost MUST be called at least once before any call to
+ // shouldAllowLocalhost or we could ignore auth checks incorrectly.
+ virtual bool shouldAllowLocalhost() const = 0;
+
// Should be called at the beginning of every new request. This performs the checks
// necessary to determine if localhost connections should be given full access.
virtual void startRequest() = 0;
diff --git a/src/mongo/db/auth/authz_session_external_state_mock.h b/src/mongo/db/auth/authz_session_external_state_mock.h
index 3db4df17de6..c884654ac91 100644
--- a/src/mongo/db/auth/authz_session_external_state_mock.h
+++ b/src/mongo/db/auth/authz_session_external_state_mock.h
@@ -43,20 +43,30 @@ namespace mongo {
public:
AuthzSessionExternalStateMock(AuthorizationManager* authzManager) :
- AuthzSessionExternalState(authzManager), _returnValue(false) {}
+ AuthzSessionExternalState(authzManager), _ignoreAuthChecksReturnValue(false),
+ _allowLocalhostReturnValue(false) {}
virtual bool shouldIgnoreAuthChecks() const {
- return _returnValue;
+ return _ignoreAuthChecksReturnValue;
+ }
+
+ virtual bool shouldAllowLocalhost() const {
+ return _allowLocalhostReturnValue;
}
void setReturnValueForShouldIgnoreAuthChecks(bool returnValue) {
- _returnValue = returnValue;
+ _ignoreAuthChecksReturnValue = returnValue;
+ }
+
+ void setReturnValueForShouldAllowLocalhost(bool returnValue) {
+ _allowLocalhostReturnValue = returnValue;
}
virtual void startRequest() {}
private:
- bool _returnValue;
+ bool _ignoreAuthChecksReturnValue;
+ bool _allowLocalhostReturnValue;
};
} // namespace mongo
diff --git a/src/mongo/db/auth/authz_session_external_state_server_common.cpp b/src/mongo/db/auth/authz_session_external_state_server_common.cpp
index 80f24004533..b5c6f6a4bc3 100644
--- a/src/mongo/db/auth/authz_session_external_state_server_common.cpp
+++ b/src/mongo/db/auth/authz_session_external_state_server_common.cpp
@@ -41,7 +41,7 @@ namespace {
} // namespace
// NOTE: we default _allowLocalhost to true under the assumption that _checkShouldAllowLocalhost
- // will always be called before any calls to shouldIgnoreAuthChecks. If this is not the case,
+ // will always be called before any calls to shouldAllowLocalhost. If this is not the case,
// it could cause a security hole.
AuthzSessionExternalStateServerCommon::AuthzSessionExternalStateServerCommon(
AuthorizationManager* authzManager) :
@@ -70,10 +70,13 @@ namespace {
}
}
- bool AuthzSessionExternalStateServerCommon::shouldIgnoreAuthChecks() const {
+ bool AuthzSessionExternalStateServerCommon::shouldAllowLocalhost() const {
ClientBasic* client = ClientBasic::getCurrent();
- return !_authzManager->isAuthEnabled() ||
- (_allowLocalhost && client->getIsLocalHostConnection());
+ return _allowLocalhost && client->getIsLocalHostConnection();
+ }
+
+ bool AuthzSessionExternalStateServerCommon::shouldIgnoreAuthChecks() const {
+ return !_authzManager->isAuthEnabled();
}
} // namespace mongo
diff --git a/src/mongo/db/auth/authz_session_external_state_server_common.h b/src/mongo/db/auth/authz_session_external_state_server_common.h
index a621fc1f651..f6e1a97f4a9 100644
--- a/src/mongo/db/auth/authz_session_external_state_server_common.h
+++ b/src/mongo/db/auth/authz_session_external_state_server_common.h
@@ -44,6 +44,7 @@ namespace mongo {
public:
virtual ~AuthzSessionExternalStateServerCommon();
+ virtual bool shouldAllowLocalhost() const;
virtual bool shouldIgnoreAuthChecks() const;
protected:
diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp
index ac10481084e..651ecb6cca9 100644
--- a/src/mongo/db/commands/authentication_commands.cpp
+++ b/src/mongo/db/commands/authentication_commands.cpp
@@ -387,6 +387,14 @@ namespace mongo {
AuthorizationSession* authSession =
ClientBasic::getCurrent()->getAuthorizationSession();
authSession->logoutDatabase(dbname);
+ if (Command::testCommandsEnabled && dbname == "admin") {
+ // Allows logging out as the internal user against the admin database, however
+ // this actually logs out of the local database as well. This is to
+ // support the auth passthrough test framework on mongos (since you can't use the
+ // local database on a mongos, so you can't logout as the internal user
+ // without this).
+ authSession->logoutDatabase("local");
+ }
return true;
}
} cmdLogout;