diff --git a/arangod/RestHandler/RestUsersHandler.cpp b/arangod/RestHandler/RestUsersHandler.cpp index 1a172fb1ec..3acf788c47 100644 --- a/arangod/RestHandler/RestUsersHandler.cpp +++ b/arangod/RestHandler/RestUsersHandler.cpp @@ -211,14 +211,14 @@ void RestUsersHandler::generateDatabaseResult(AuthInfo* authInfo, data.add(c->name(), VPackValue("undefined")); } }); - lvl = authInfo->canUseCollection(user, vocbase->name(), "*"); + lvl = authInfo->canUseCollectionNoLock(user, vocbase->name(), "*"); data.add("*", VPackValue(convertFromAuthLevel(lvl))); } else if (lvl != AuthLevel::NONE) { // hide db's without access data.add(vocbase->name(), VPackValue(str)); } }); if (full) { - AuthLevel lvl = authInfo->canUseDatabase(user, "*"); + AuthLevel lvl = authInfo->canUseDatabaseNoLock(user, "*"); data("*", VPackValue(VPackValueType::Object))( "permission", VPackValue(convertFromAuthLevel(lvl)))(); } diff --git a/arangod/VocBase/AuthInfo.cpp b/arangod/VocBase/AuthInfo.cpp index 797d71806f..0cf1435bd5 100644 --- a/arangod/VocBase/AuthInfo.cpp +++ b/arangod/VocBase/AuthInfo.cpp @@ -208,8 +208,9 @@ static VPackBuilder QueryUser(aql::QueryRegistry* queryRegistry, if (doc.isExternal()) { doc = doc.resolveExternals(); } - - return VPackBuilder(doc); + VPackBuilder result; + result.add(doc); + return result; } static void ConvertLegacyFormat(VPackSlice doc, VPackBuilder& result) { @@ -680,6 +681,7 @@ Result AuthInfo::removeAllUsers() { Result res; { + MUTEX_LOCKER(locker, _loadFromDBLock); WRITE_LOCKER(guard, _authInfoLock); for (auto const& pair : _authInfo) { @@ -698,7 +700,6 @@ Result AuthInfo::removeAllUsers() { // do not get into race conditions with loadFromDB { - MUTEX_LOCKER(locker, _loadFromDBLock); _authInfo.clear(); _authBasicCache.clear(); _outdated = true; @@ -912,6 +913,17 @@ AuthLevel AuthInfo::canUseDatabase(std::string const& username, return level; } +AuthLevel AuthInfo::canUseDatabaseNoLock(std::string const& username, + std::string const& dbname) { + AuthLevel level = configuredDatabaseAuthLevelInternal(username, dbname, 0); + static_assert(AuthLevel::RO < AuthLevel::RW, "ro < rw"); + if (level > AuthLevel::RO && !ServerState::writeOpsEnabled()) { + return AuthLevel::RO; + } + return level; +} + + // internal method called by configuredCollectionAuthLevel // asserts that collection name is non-empty and already translated // from collection id to name @@ -986,6 +998,29 @@ AuthLevel AuthInfo::canUseCollection(std::string const& username, return level; } +AuthLevel AuthInfo::canUseCollectionNoLock(std::string const& username, + std::string const& dbname, + std::string const& coll) { + if (coll.empty()) { + // no collection name given + return AuthLevel::NONE; + } + + AuthLevel level; + if (coll[0] >= '0' && coll[0] <= '9') { + std::string tmpColl = DatabaseFeature::DATABASE->translateCollectionName(dbname, coll); + level = configuredCollectionAuthLevelInternal(username, dbname, tmpColl, 0); + } else { + level = configuredCollectionAuthLevelInternal(username, dbname, coll, 0); + } + + static_assert(AuthLevel::RO < AuthLevel::RW, "ro < rw"); + if (level > AuthLevel::RO && !ServerState::writeOpsEnabled()) { + return AuthLevel::RO; + } + return level; +} + // public called from HttpCommTask.cpp and VstCommTask.cpp diff --git a/arangod/VocBase/AuthInfo.h b/arangod/VocBase/AuthInfo.h index 73341969ad..459adc42e2 100644 --- a/arangod/VocBase/AuthInfo.h +++ b/arangod/VocBase/AuthInfo.h @@ -126,6 +126,16 @@ class AuthInfo { std::string const& dbname, std::string const& coll); + // No Lock variants of the above to be used in callbacks + // Use with CARE! You need to make sure that the lock + // is held from outside. + AuthLevel canUseDatabaseNoLock(std::string const& username, + std::string const& dbname); + AuthLevel canUseCollectionNoLock(std::string const& username, + std::string const& dbname, + std::string const& coll); + + void setJwtSecret(std::string const&); std::string jwtSecret(); std::string generateJwt(VPackBuilder const&);