Skip to content

Commit

Permalink
Add initialize method to AuthorizationManager to move admin user exis…
Browse files Browse the repository at this point in the history
…tance check outside of the constructor. SERVER-7126 SERVER-7572
  • Loading branch information
stbrody committed Nov 9, 2012
1 parent 02e35bf commit 7e7c9c3
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 14 deletions.
25 changes: 19 additions & 6 deletions src/mongo/db/auth/auth_external_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,32 @@

#include "mongo/db/auth/auth_external_state_impl.h"

#include "mongo/base/status.h"
#include "mongo/client/dbclientinterface.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/client.h"
#include "mongo/util/debug_util.h"

namespace mongo {

AuthExternalStateImpl::AuthExternalStateImpl(DBClientBase* adminDBConnection) {
_adminUserExists = AuthorizationManager::hasPrivilegeDocument(adminDBConnection, "admin");
if (!_adminUserExists) {
log() << "note: no users configured in admin.system.users, allowing localhost access"
<< endl;
Status AuthExternalStateImpl::initialize(DBClientBase* adminDBConnection) {
try {
_adminUserExists = AuthorizationManager::hasPrivilegeDocument(adminDBConnection,
"admin");
} catch (DBException& e) {
return Status(ErrorCodes::InternalError,
mongoutils::str::stream() << "An error occurred while checking for the "
"existence of an admin user: " << e.what(),
0);
}
ONCE {
if (!_adminUserExists) {
log() << "note: no users configured in admin.system.users, allowing localhost access"
<< endl;
}
}
return Status::OK();
}
AuthExternalStateImpl::~AuthExternalStateImpl() {}

bool AuthExternalStateImpl::shouldIgnoreAuthChecks() const {
// TODO: uncomment part that checks if connection is localhost by looking in cc()
Expand Down
8 changes: 8 additions & 0 deletions src/mongo/db/auth/auth_external_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
#include "mongo/client/dbclientinterface.h"

namespace mongo {
Expand All @@ -40,6 +41,13 @@ namespace mongo {
// or the connection is a "god" connection.
virtual bool shouldIgnoreAuthChecks() const = 0;

// adminDBConnection is a connection that can be used to access the admin database. It is
// used to determine if there are any admin users configured for the cluster, and thus if
// localhost connections should be given special admin access.
// This function *must* be called on any new AuthExternalState, after the constructor but
// before any other methods are called on the AuthExternalState.
virtual Status initialize(DBClientBase* adminDBConnection) = 0;

protected:
AuthExternalState() {}; // This class should never be instantiated directly.
};
Expand Down
17 changes: 10 additions & 7 deletions src/mongo/db/auth/auth_external_state_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
#include "mongo/client/dbclientinterface.h"
#include "mongo/db/auth/auth_external_state.h"

Expand All @@ -30,20 +31,22 @@ namespace mongo {

public:

// adminDBConnection is a connection that can be used to access the admin database. It is
// used to determine if there are any admin users configured for the cluster, and thus if
// localhost connections should be given special admin access.
// adminDBConnection is used only in the constructor, no pointer to it is stored, so it
// can be deleted as soon as the constructor returns.
AuthExternalStateImpl(DBClientBase* adminDBConnection);
virtual ~AuthExternalStateImpl();
AuthExternalStateImpl() {};
virtual ~AuthExternalStateImpl() {};

// 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 admin users,
// or the connection is a "god" connection.
virtual bool shouldIgnoreAuthChecks() const;

// adminDBConnection is a connection that can be used to access the admin database. It is
// used to determine if there are any admin users configured for the cluster, and thus if
// localhost connections should be given special admin access.
// This function *must* be called on any new AuthExternalState, after the constructor but
// before any other methods are called on the AuthExternalState.
virtual Status initialize(DBClientBase* adminDBConnection);

private:

bool _adminUserExists;
Expand Down
5 changes: 5 additions & 0 deletions src/mongo/db/auth/auth_external_state_mock.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#pragma once

#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
#include "mongo/client/dbclientinterface.h"
#include "mongo/db/auth/auth_external_state.h"

namespace mongo {
Expand All @@ -38,6 +40,9 @@ namespace mongo {
_returnValue = returnValue;
}

// This is a no-op for the mock
virtual Status initialize(DBClientBase* adminDBConnection) { return Status::OK(); }

private:
bool _returnValue;
};
Expand Down
19 changes: 18 additions & 1 deletion src/mongo/db/auth/authorization_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,27 @@ namespace mongo {
return Status::OK();
}

AuthorizationManager::AuthorizationManager(AuthExternalState* externalState) {
AuthorizationManager::AuthorizationManager(AuthExternalState* externalState) :
_initialized(false) {
_externalState.reset(externalState);
}

AuthorizationManager::~AuthorizationManager(){}

Status AuthorizationManager::initialize(DBClientBase* adminDBConnection) {
if (_initialized) {
// This should never happen.
return Status(ErrorCodes::InternalError,
"AuthorizationManager already initialized!",
0);
}
Status status = _externalState->initialize(adminDBConnection);
if (status == Status::OK()) {
_initialized = true;
}
return status;
}

void AuthorizationManager::addAuthorizedPrincipal(Principal* principal) {
_authenticatedPrincipals.add(principal);
}
Expand Down Expand Up @@ -266,6 +281,8 @@ namespace mongo {

const Principal* AuthorizationManager::checkAuthorization(const std::string& resource,
ActionType action) const {
massert(16470, "AuthorizationManager has not been initialized!", _initialized);

if (_externalState->shouldIgnoreAuthChecks()) {
return &specialAdminPrincipal;
}
Expand Down
8 changes: 8 additions & 0 deletions src/mongo/db/auth/authorization_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ namespace mongo {
explicit AuthorizationManager(AuthExternalState* externalState);
~AuthorizationManager();

// adminDBConnection is a connection that can be used to access the admin database. It is
// used to determine if there are any admin users configured for the cluster, and thus if
// localhost connections should be given special admin access.
// This function *must* be called on any new AuthorizationManager, after the constructor but
// before any other methods are called on the AuthorizationManager.
Status initialize(DBClientBase* adminDBConnection);

// Takes ownership of the principal (by putting into _authenticatedPrincipals).
void addAuthorizedPrincipal(Principal* principal);
// Removes and deletes the given principal from the set of authenticated principals.
Expand Down Expand Up @@ -101,6 +108,7 @@ namespace mongo {
PrivilegeSet _acquiredPrivileges;
// All principals who have been authenticated on this connection
PrincipalSet _authenticatedPrincipals;
bool _initialized;
};

} // namespace mongo
2 changes: 2 additions & 0 deletions src/mongo/db/auth/authorization_manager_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace {
AcquiredPrivilege allDBsWritePrivilege(Privilege("*", actions), principal);
AuthExternalStateMock* externalState = new AuthExternalStateMock();
AuthorizationManager authManager(externalState);
authManager.initialize(NULL);

ASSERT_NULL(authManager.checkAuthorization("test", ActionType::insert));
externalState->setReturnValueForShouldIgnoreAuthChecks(true);
Expand All @@ -60,6 +61,7 @@ namespace {
TEST(AuthorizationManagerTest, GrantInternalAuthorization) {
AuthExternalStateMock* externalState = new AuthExternalStateMock();
AuthorizationManager authManager(externalState);
authManager.initialize(NULL);

ASSERT_NULL(authManager.checkAuthorization("test", ActionType::insert));
ASSERT_NULL(authManager.checkAuthorization("test", ActionType::replSetHeartbeat));
Expand Down

0 comments on commit 7e7c9c3

Please sign in to comment.