/**
* Copyright (C) 2018 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#pragma once
#include
#include
#include "mongo/base/disallow_copying.h"
#include "mongo/base/secure_allocator.h"
#include "mongo/base/shim.h"
#include "mongo/base/status.h"
#include "mongo/bson/mutable/element.h"
#include "mongo/bson/oid.h"
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/privilege_format.h"
#include "mongo/db/auth/resource_pattern.h"
#include "mongo/db/auth/role_graph.h"
#include "mongo/db/auth/user.h"
#include "mongo/db/auth/user_name.h"
#include "mongo/db/auth/user_name_hash.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/server_options.h"
#include "mongo/stdx/condition_variable.h"
#include "mongo/stdx/functional.h"
#include "mongo/stdx/mutex.h"
#include "mongo/stdx/unordered_map.h"
namespace mongo {
class AuthorizationSession;
class AuthzManagerExternalState;
class OperationContext;
class ServiceContext;
class UserDocumentParser;
/**
* Internal secret key info.
*/
struct AuthInfo {
UserHandle user;
};
extern AuthInfo internalSecurity; // set at startup and not changed after initialization.
/**
* How user management functions should structure the BSON representation of privileges and roles.
*/
enum class AuthenticationRestrictionsFormat {
kOmit, // AuthenticationRestrictions should not be included in the BSON representation.
kShow, // AuthenticationRestrictions should be included in the BSON representation.
};
/**
* Contains server/cluster-wide information about Authorization.
*/
class AuthorizationManager {
AuthorizationManager(const AuthorizationManager&) = delete;
AuthorizationManager& operator=(const AuthorizationManager&) = delete;
public:
static AuthorizationManager* get(ServiceContext* service);
static AuthorizationManager* get(ServiceContext& service);
static void set(ServiceContext* service, std::unique_ptr authzManager);
virtual ~AuthorizationManager() = default;
AuthorizationManager() = default;
static MONGO_DECLARE_SHIM(()->std::unique_ptr) create;
static constexpr StringData USER_NAME_FIELD_NAME = "user"_sd;
static constexpr StringData USER_DB_FIELD_NAME = "db"_sd;
static constexpr StringData ROLE_NAME_FIELD_NAME = "role"_sd;
static constexpr StringData ROLE_DB_FIELD_NAME = "db"_sd;
static constexpr StringData PASSWORD_FIELD_NAME = "pwd"_sd;
static constexpr StringData V1_USER_NAME_FIELD_NAME = "user"_sd;
static constexpr StringData V1_USER_SOURCE_FIELD_NAME = "userSource"_sd;
static const NamespaceString adminCommandNamespace;
static const NamespaceString rolesCollectionNamespace;
static const NamespaceString usersAltCollectionNamespace;
static const NamespaceString usersBackupCollectionNamespace;
static const NamespaceString usersCollectionNamespace;
static const NamespaceString versionCollectionNamespace;
static const NamespaceString defaultTempUsersCollectionNamespace; // for mongorestore
static const NamespaceString defaultTempRolesCollectionNamespace; // for mongorestore
/**
* Status to be returned when authentication fails. Being consistent about our returned Status
* prevents information leakage.
*/
static const Status authenticationFailedStatus;
/**
* Query to match the auth schema version document in the versionCollectionNamespace.
*/
static const BSONObj versionDocumentQuery;
/**
* Name of the field in the auth schema version document containing the current schema
* version.
*/
static constexpr StringData schemaVersionFieldName = "currentVersion"_sd;
/**
* Value used to represent that the schema version is not cached or invalid.
*/
static const int schemaVersionInvalid = 0;
/**
* Auth schema version for MongoDB v2.4 and prior.
*/
static const int schemaVersion24 = 1;
/**
* Auth schema version for MongoDB v2.6 during the upgrade process. Same as
* schemaVersion26Final, except that user documents are found in admin.new.users, and user
* management commands are disabled.
*/
static const int schemaVersion26Upgrade = 2;
/**
* Auth schema version for MongoDB 2.6 and 3.0 MONGODB-CR/SCRAM mixed auth mode.
* Users are stored in admin.system.users, roles in admin.system.roles.
*/
static const int schemaVersion26Final = 3;
/**
* Auth schema version for MongoDB 3.0 SCRAM only mode.
* Users are stored in admin.system.users, roles in admin.system.roles.
* MONGODB-CR credentials have been replaced with SCRAM credentials in the user documents.
*/
static const int schemaVersion28SCRAM = 5;
/**
* Returns a new AuthorizationSession for use with this AuthorizationManager.
*/
virtual std::unique_ptr makeAuthorizationSession() = 0;
/**
* Sets whether or not startup AuthSchema validation checks should be applied in this manager.
*/
virtual void setShouldValidateAuthSchemaOnStartup(bool validate) = 0;
/**
* Returns true if startup AuthSchema validation checks should be applied in this manager.
*/
virtual bool shouldValidateAuthSchemaOnStartup() = 0;
/**
* Sets whether or not access control enforcement is enabled for this manager.
*/
virtual void setAuthEnabled(bool enabled) = 0;
/**
* Returns true if access control is enabled for this manager .
*/
virtual bool isAuthEnabled() const = 0;
/**
* Returns via the output parameter "version" the version number of the authorization
* system. Returns Status::OK() if it was able to successfully fetch the current
* authorization version. If it has problems fetching the most up to date version it
* returns a non-OK status. When returning a non-OK status, *version will be set to
* schemaVersionInvalid (0).
*/
virtual Status getAuthorizationVersion(OperationContext* opCtx, int* version) = 0;
/**
* Returns the user cache generation identifier.
*/
virtual OID getCacheGeneration() = 0;
/**
* Returns true if there exists at least one privilege document in the system.
* Used by the AuthorizationSession to determine whether localhost connections should be
* granted special access to bootstrap the system.
* NOTE: If this method ever returns true, the result is cached in _privilegeDocsExist,
* meaning that once this method returns true it will continue to return true for the
* lifetime of this process, even if all users are subsequently dropped from the system.
*/
virtual bool hasAnyPrivilegeDocuments(OperationContext* opCtx) = 0;
/**
* Delegates method call to the underlying AuthzManagerExternalState.
*/
virtual Status getUserDescription(OperationContext* opCtx,
const UserName& userName,
BSONObj* result) = 0;
/**
* Delegates method call to the underlying AuthzManagerExternalState.
*/
virtual Status getRoleDescription(OperationContext* opCtx,
const RoleName& roleName,
PrivilegeFormat privilegeFormat,
AuthenticationRestrictionsFormat,
BSONObj* result) = 0;
/**
* Convenience wrapper for getRoleDescription() defaulting formats to kOmit.
*/
Status getRoleDescription(OperationContext* ctx, const RoleName& roleName, BSONObj* result) {
return getRoleDescription(
ctx, roleName, PrivilegeFormat::kOmit, AuthenticationRestrictionsFormat::kOmit, result);
}
/**
* Delegates method call to the underlying AuthzManagerExternalState.
*/
virtual Status getRolesDescription(OperationContext* opCtx,
const std::vector& roleName,
PrivilegeFormat privilegeFormat,
AuthenticationRestrictionsFormat,
BSONObj* result) = 0;
/**
* Delegates method call to the underlying AuthzManagerExternalState.
*/
virtual Status getRoleDescriptionsForDB(OperationContext* opCtx,
StringData dbname,
PrivilegeFormat privilegeFormat,
AuthenticationRestrictionsFormat,
bool showBuiltinRoles,
std::vector* result) = 0;
/**
* Returns a Status or UserHandle for the given userName. If the user cache already has a
* user object for this user, it returns a handle from the cache, otherwise it reads the
* user document from disk or LDAP - this may block for a long time.
*
* The returned user may be invalid by the time the caller gets access to it.
*/
virtual StatusWith acquireUser(OperationContext* opCtx,
const UserName& userName) = 0;
/**
* Marks the given user as invalid and removes it from the user cache.
*/
virtual void invalidateUserByName(OperationContext* opCtx, const UserName& user) = 0;
/**
* Invalidates all users who's source is "dbname" and removes them from the user cache.
*/
virtual void invalidateUsersFromDB(OperationContext* opCtx, StringData dbname) = 0;
/**
* Initializes the authorization manager. Depending on what version the authorization
* system is at, this may involve building up the user cache and/or the roles graph.
* Call this function at startup and after resynchronizing a slave/secondary.
*/
virtual Status initialize(OperationContext* opCtx) = 0;
/**
* Invalidates all of the contents of the user cache.
*/
virtual void invalidateUserCache(OperationContext* opCtx) = 0;
/**
* Parses privDoc and fully initializes the user object (credentials, roles, and privileges)
* with the information extracted from the privilege document.
* This should never be called from outside the AuthorizationManager - the only reason it's
* public instead of private is so it can be unit tested.
*/
virtual Status _initializeUserFromPrivilegeDocument(User* user, const BSONObj& privDoc) = 0;
/**
* Hook called by replication code to let the AuthorizationManager observe changes
* to relevant collections.
*/
virtual void logOp(OperationContext* opCtx,
const char* opstr,
const NamespaceString& nss,
const BSONObj& obj,
const BSONObj* patt) = 0;
/*
* Represents a user in the user cache.
*/
struct CachedUserInfo {
UserName userName; // The username of the user
bool active; // Whether the user is currently in use by a thread (a thread has
// called acquireUser and still owns the returned shared_ptr)
};
virtual std::vector getUserCacheInfo() const = 0;
virtual void setInUserManagementCommand(OperationContext* opCtx, bool val) = 0;
};
} // namespace mongo