diff options
author | Amalia Hawkins <amalia.hawkins@10gen.com> | 2014-04-21 18:43:25 -0400 |
---|---|---|
committer | Amalia Hawkins <amalia.hawkins@10gen.com> | 2014-05-22 20:29:39 -0400 |
commit | 1b4b52a9d413e145478a303b63ab760894938c80 (patch) | |
tree | 3286cdd06d688d4345a80215f84b4674a398b753 /src/mongo/db | |
parent | 7a85cae38fba537980d6c9fc573ef077fd2df74e (diff) | |
download | mongo-1b4b52a9d413e145478a303b63ab760894938c80.tar.gz |
SERVER-12621 narrow the localhost exception when auth is enabled
Diffstat (limited to 'src/mongo/db')
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; |