diff --git a/arangod/HttpServer/HttpHandlerFactory.cpp b/arangod/HttpServer/HttpHandlerFactory.cpp index f51967d200..669ed27d33 100644 --- a/arangod/HttpServer/HttpHandlerFactory.cpp +++ b/arangod/HttpServer/HttpHandlerFactory.cpp @@ -94,8 +94,6 @@ bool HttpHandlerFactory::isMaintenance() { //////////////////////////////////////////////////////////////////////////////// /// @brief authenticates a new request -/// -/// wrapper method that will consider disabled authentication etc. //////////////////////////////////////////////////////////////////////////////// GeneralResponse::ResponseCode HttpHandlerFactory::authenticateRequest( diff --git a/arangod/RestServer/VocbaseContext.cpp b/arangod/RestServer/VocbaseContext.cpp index 79e583984f..6544641141 100644 --- a/arangod/RestServer/VocbaseContext.cpp +++ b/arangod/RestServer/VocbaseContext.cpp @@ -92,15 +92,35 @@ GeneralResponse::ResponseCode VocbaseContext::authenticate() { } std::string const& path = _request->requestPath(); + // mop: inside authenticateRequest() _request->user will be populated GeneralResponse::ResponseCode result = authenticateRequest(); + bool forceOpen = false; + if (result == GeneralResponse::ResponseCode::UNAUTHORIZED || result == GeneralResponse::ResponseCode::FORBIDDEN) { if (StringUtils::isPrefix(path, "/_open/") || StringUtils::isPrefix(path, "/_admin/aardvark/") || path == "/") { // mop: these paths are always callable...they will be able to check req.user when it could be validated result = GeneralResponse::ResponseCode::OK; + forceOpen = true; } } + + // check that we are allowed to see the database + if (result == GeneralResponse::ResponseCode::OK && !forceOpen) { + std::string const& username = _request->user(); + std::string const& dbname = _request->databaseName(); + + if (!username.empty() || !dbname.empty()) { + AuthLevel level = + RestServerFeature::AUTH_INFO.canUseDatabase(username, dbname); + + if (level != AuthLevel::RW) { + result = GeneralResponse::ResponseCode::UNAUTHORIZED; + } + } + } + return result; } diff --git a/arangod/VocBase/AuthInfo.cpp b/arangod/VocBase/AuthInfo.cpp index 3a582a90a5..09c67a908d 100644 --- a/arangod/VocBase/AuthInfo.cpp +++ b/arangod/VocBase/AuthInfo.cpp @@ -96,13 +96,53 @@ static AuthEntry CreateAuthEntry(VPackSlice const& slice) { bool mustChange = VelocyPackHelper::getBooleanValue(slice, "changePassword", false); + // extract "databases" attribute + VPackSlice const databasesSlice = authDataSlice.get("databases"); + std::unordered_map databases; + AuthLevel allDatabases = AuthLevel::NONE; + + if (databasesSlice.isObject()) { + for (auto const& obj : VPackObjectIterator(databasesSlice)) { + std::string const key = obj.key.copyString(); + + ValueLength length; + char const* value = obj.value.getString(length); + + if (TRI_CaseEqualString(value, "rw", 2)) { + if (key == "*") { + allDatabases = AuthLevel::RW; + } else { + databases.emplace(key, AuthLevel::RW); + } + } + else if (TRI_CaseEqualString(value, "ro", 2)) { + if (key == "*") { + allDatabases = AuthLevel::RO; + } else { + databases.emplace(key, AuthLevel::RO); + } + } + } + } + + // build authentication entry return AuthEntry(userSlice.copyString(), methodSlice.copyString(), - saltSlice.copyString(), hashSlice.copyString(), active, - mustChange); + saltSlice.copyString(), hashSlice.copyString(), + databases, allDatabases, active, mustChange); } AuthLevel AuthEntry::canUseDatabase(std::string const& dbname) const { - return AuthLevel::NONE; + if (_allDatabases == AuthLevel::RW) { + return _allDatabases; + } + + auto const& it = _databases.find(dbname); + + if (it == _databases.end()) { + return _allDatabases; + } + + return it->second; } void AuthInfo::clear() { diff --git a/arangod/VocBase/AuthInfo.h b/arangod/VocBase/AuthInfo.h index 119f923d16..1737018cdc 100644 --- a/arangod/VocBase/AuthInfo.h +++ b/arangod/VocBase/AuthInfo.h @@ -39,17 +39,20 @@ enum class AuthLevel { class AuthEntry { public: - AuthEntry() : _active(false), _mustChange(false) {} + AuthEntry() : _active(false), _mustChange(false) {} AuthEntry(std::string const& username, std::string const& passwordMethod, std::string const& passwordSalt, std::string const& passwordHash, - bool active, bool mustChange) + std::unordered_map databases, AuthLevel allDatabases, + bool active, bool mustChange) : _username(username), _passwordMethod(passwordMethod), _passwordSalt(passwordSalt), _passwordHash(passwordHash), _active(active), - _mustChange(mustChange) {} + _mustChange(mustChange), + _databases(databases), + _allDatabases(allDatabases) {} public: std::string const& username() const { return _username; } @@ -72,6 +75,8 @@ class AuthEntry { std::string _passwordHash; bool _active; bool _mustChange; + std::unordered_map _databases; + AuthLevel _allDatabases; }; class AuthResult {