//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Dr. Frank Celler //////////////////////////////////////////////////////////////////////////////// #ifndef ARANGOD_AUTHENTICATION_USER_MANAGER_H #define ARANGOD_AUTHENTICATION_USER_MANAGER_H 1 #include "Auth/Common.h" #include "Auth/User.h" #include "ApplicationFeatures/ApplicationFeature.h" #include "Basics/Mutex.h" #include "Basics/ReadWriteLock.h" #include "Basics/Result.h" #include "Rest/CommonDefines.h" #include #include namespace arangodb { namespace aql { class QueryRegistry; } namespace basics { template class ReadLocker; } namespace auth { class Handler; typedef std::unordered_map UserMap; /// UserManager is the sole point of access for users and permissions /// stored in `_system/_users` as well as in external authentication /// systems like LDAP. The permissions are cached locally if possible, /// to avoid unnecessary disk access. An instance of this should only /// exist on coordinators and single servers. class UserManager { public: explicit UserManager(); #ifdef USE_ENTERPRISE explicit UserManager(std::unique_ptr); #endif ~UserManager() = default; public: typedef std::function UserCallback; typedef std::function ConstUserCallback; void setQueryRegistry(aql::QueryRegistry* registry) { TRI_ASSERT(registry != nullptr); _queryRegistry = registry; } /// Tells coordinator to reload its data. Only called in HeartBeat thread void setGlobalVersion(uint64_t version) { _globalVersion.store(version, std::memory_order_release); } /// @brief reload user cache and token caches void triggerLocalReload() { _globalVersion.fetch_add(1, std::memory_order_release); } /// @brief used for caching uint64_t globalVersion() { return _globalVersion.load(std::memory_order_acquire); } /// Trigger eventual reload on all other coordinators (and in TokenCache) void triggerGlobalReload(); /// Trigger cache revalidation after user restore void triggerCacheRevalidation(); /// Create the root user with a default password, will fail if the user /// already exists. Only ever call if you can guarantee to be in charge void createRootUser(); velocypack::Builder allUsers(); /// Add user from arangodb, do not use for LDAP users Result storeUser(bool replace, std::string const& user, std::string const& pass, bool active, velocypack::Slice extras); /// Enumerate list of all users Result enumerateUsers(std::function&&, bool retryOnConflict); /// Update specific user Result updateUser(std::string const& user, UserCallback&&); /// Access user without modifying it Result accessUser(std::string const& user, ConstUserCallback&&); /// @brief does this user exists in the db bool userExists(std::string const& user); /// Serialize user into legacy format for REST API velocypack::Builder serializeUser(std::string const& user); Result removeUser(std::string const& user); Result removeAllUsers(); /// Convenience method to check a password bool checkPassword(std::string const& username, std::string const& password); /// Convenience method to refresh user rights /// returns true if the user was actually refreshed and the caller may /// need to update its own caches #ifdef USE_ENTERPRISE bool refreshUser(std::string const& username); #else inline bool refreshUser(std::string const& username) { return false; } #endif auth::Level databaseAuthLevel(std::string const& username, std::string const& dbname, bool configured = false); auth::Level collectionAuthLevel(std::string const& username, std::string const& dbname, std::string const& coll, bool configured = false); /// Overwrite internally cached permissions, only use /// for testing purposes void setAuthInfo(auth::UserMap const& userEntryMap); #ifdef USE_ENTERPRISE /// @brief apply roles to all users in cache void applyRolesToAllUsers(); /// @brief apply roles to user, must lock _userCacheLock void applyRoles(auth::User&) const; /// @brief Check authorization with external system /// @param userCached is the user cached locally /// @param a read guard which may need to be released bool checkPasswordExt(std::string const& username, std::string const& password, bool userCached, basics::ReadLocker& readGuard); #endif private: /// @brief load users and permissions from local database void loadFromDB(); /// @brief store or replace user object Result storeUserInternal(auth::User const& user, bool replace); private: /// Protected the sync process from db, always lock /// before locking _userCacheLock Mutex _loadFromDBLock; /// Protect the _userCache access basics::ReadWriteLock _userCacheLock; /// @brief used to update caches std::atomic _globalVersion; std::atomic _internalVersion; /// Caches permissions and other user info UserMap _userCache; aql::QueryRegistry* _queryRegistry; #ifdef USE_ENTERPRISE /// iterface to external authentication systems like LDAP std::unique_ptr _authHandler; #endif }; } // namespace auth } // namespace arangodb #endif