mirror of https://gitee.com/bigwinds/arangodb
Various authentication related issues (#2824)
This commit is contained in:
parent
17a8049e50
commit
f50a36181d
|
@ -81,8 +81,7 @@ struct LPComputation : public VertexComputation<LPValue, int8_t, uint64_t> {
|
|||
uint64_t newCommunity = mutableVertexData()->currentCommunity;
|
||||
if (messages.size() == 1) {
|
||||
newCommunity = std::min(**messages, newCommunity);
|
||||
}
|
||||
if (messages.size() > 1) {
|
||||
} else if (messages.size() > 1) {
|
||||
newCommunity = mostFrequent(messages);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,16 +22,17 @@
|
|||
|
||||
#include "InitDatabaseFeature.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "Basics/FileUtils.h"
|
||||
#include "Basics/terminal-utils.h"
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "Logger/LoggerFeature.h"
|
||||
#include "ProgramOptions/ProgramOptions.h"
|
||||
#include "ProgramOptions/Section.h"
|
||||
#include "RestServer/DatabasePathFeature.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::application_features;
|
||||
using namespace arangodb::basics;
|
||||
|
@ -71,6 +72,7 @@ void InitDatabaseFeature::validateOptions(
|
|||
|
||||
if (_initDatabase || _restoreAdmin) {
|
||||
ApplicationServer::forceDisableFeatures(_nonServerFeatures);
|
||||
ServerState::instance()->setRole(ServerState::ROLE_SINGLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,7 +142,7 @@ std::string InitDatabaseFeature::readPassword(std::string const& message) {
|
|||
void InitDatabaseFeature::checkEmptyDatabase() {
|
||||
auto database = ApplicationServer::getFeature<DatabasePathFeature>("DatabasePath");
|
||||
std::string path = database->directory();
|
||||
std::string journals = database->subdirectoryName("journals");
|
||||
std::string serverFile = database->subdirectoryName("SERVER");
|
||||
|
||||
bool empty = false;
|
||||
std::string message;
|
||||
|
@ -153,10 +155,10 @@ void InitDatabaseFeature::checkEmptyDatabase() {
|
|||
goto doexit;
|
||||
}
|
||||
|
||||
if (FileUtils::exists(journals)) {
|
||||
if (!FileUtils::isDirectory(journals)) {
|
||||
if (FileUtils::exists(serverFile)) {
|
||||
if (FileUtils::isDirectory(serverFile)) {
|
||||
message =
|
||||
"database journals path '" + journals + "' is not a directory";
|
||||
"database SERVER '" + serverFile + "' is not a file";
|
||||
code = EXIT_FAILURE;
|
||||
goto doexit;
|
||||
}
|
||||
|
@ -168,7 +170,7 @@ void InitDatabaseFeature::checkEmptyDatabase() {
|
|||
}
|
||||
|
||||
if (!empty) {
|
||||
message = "database already initialized, refusing to change root user";
|
||||
message = "database already initialized, refusing to initialize it again";
|
||||
goto doexit;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "UpgradeFeature.h"
|
||||
|
||||
#include "Cluster/ClusterFeature.h"
|
||||
#include "GeneralServer/AuthenticationFeature.h"
|
||||
#include "Logger/Logger.h"
|
||||
#include "ProgramOptions/ProgramOptions.h"
|
||||
#include "ProgramOptions/Section.h"
|
||||
|
@ -101,15 +102,46 @@ void UpgradeFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
|||
void UpgradeFeature::start() {
|
||||
auto init =
|
||||
ApplicationServer::getFeature<InitDatabaseFeature>("InitDatabase");
|
||||
AuthInfo *ai = AuthenticationFeature::INSTANCE->authInfo();
|
||||
|
||||
// upgrade the database
|
||||
if (_upgradeCheck) {
|
||||
upgradeDatabase(init->defaultPassword());
|
||||
upgradeDatabase();
|
||||
|
||||
if (!init->restoreAdmin() && !init->defaultPassword().empty()) {
|
||||
ai->updateUser("root", [&](AuthUserEntry& entry) {
|
||||
entry.updatePassword(init->defaultPassword());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// change admin user
|
||||
if (init->restoreAdmin()) {
|
||||
changeAdminPassword(init->defaultPassword());
|
||||
Result res;
|
||||
|
||||
res = ai->removeAllUsers();
|
||||
|
||||
if (res.fail()) {
|
||||
LOG_TOPIC(WARN, arangodb::Logger::FIXME) << "failed to create clear users: "
|
||||
<< res.errorMessage();
|
||||
*_result = EXIT_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
res = ai->storeUser(true, "root", init->defaultPassword(), true);
|
||||
|
||||
if (res.fail() && res.errorNumber() == TRI_ERROR_USER_NOT_FOUND) {
|
||||
res = ai->storeUser(false, "root", init->defaultPassword(), true);
|
||||
}
|
||||
|
||||
if (res.fail()) {
|
||||
LOG_TOPIC(WARN, arangodb::Logger::FIXME) << "failed to create root user: "
|
||||
<< res.errorMessage();
|
||||
*_result = EXIT_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
*_result = EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// and force shutdown
|
||||
|
@ -117,71 +149,12 @@ void UpgradeFeature::start() {
|
|||
if (init->isInitDatabase()) {
|
||||
*_result = EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
server()->beginShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void UpgradeFeature::changeAdminPassword(std::string const& defaultPassword) {
|
||||
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "starting to restore admin user";
|
||||
|
||||
auto* systemVocbase = DatabaseFeature::DATABASE->systemDatabase();
|
||||
|
||||
// enter context and isolate
|
||||
{
|
||||
V8Context* context =
|
||||
V8DealerFeature::DEALER->enterContext(systemVocbase, true, 0);
|
||||
|
||||
if (context == nullptr) {
|
||||
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "could not enter context #0";
|
||||
FATAL_ERROR_EXIT();
|
||||
}
|
||||
|
||||
TRI_DEFER(V8DealerFeature::DEALER->exitContext(context));
|
||||
|
||||
{
|
||||
v8::HandleScope scope(context->_isolate);
|
||||
auto localContext =
|
||||
v8::Local<v8::Context>::New(context->_isolate, context->_context);
|
||||
localContext->Enter();
|
||||
|
||||
{
|
||||
v8::Context::Scope contextScope(localContext);
|
||||
|
||||
// run upgrade script
|
||||
LOG_TOPIC(DEBUG, arangodb::Logger::FIXME) << "running admin recreation script";
|
||||
|
||||
// special check script to be run just once in first thread (not in
|
||||
// all) but for all databases
|
||||
v8::HandleScope scope(context->_isolate);
|
||||
|
||||
v8::Handle<v8::Object> args = v8::Object::New(context->_isolate);
|
||||
|
||||
args->Set(TRI_V8_ASCII_STRING2(context->_isolate, "password"),
|
||||
TRI_V8_STD_STRING2(context->_isolate, defaultPassword));
|
||||
|
||||
localContext->Global()->Set(
|
||||
TRI_V8_ASCII_STRING2(context->_isolate, "UPGRADE_ARGS"), args);
|
||||
|
||||
auto startupLoader = V8DealerFeature::DEALER->startupLoader();
|
||||
|
||||
startupLoader->executeGlobalScript(context->_isolate, localContext,
|
||||
"server/restore-admin-user.js");
|
||||
}
|
||||
|
||||
// finally leave the context. otherwise v8 will crash with assertion
|
||||
// failure when we delete the context locker below
|
||||
localContext->Exit();
|
||||
}
|
||||
}
|
||||
|
||||
// and return from the context
|
||||
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "finished to restore admin user";
|
||||
|
||||
*_result = EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void UpgradeFeature::upgradeDatabase(std::string const& defaultPassword) {
|
||||
void UpgradeFeature::upgradeDatabase() {
|
||||
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "starting database init/upgrade";
|
||||
|
||||
DatabaseFeature* databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
|
||||
|
@ -224,8 +197,6 @@ void UpgradeFeature::upgradeDatabase(std::string const& defaultPassword) {
|
|||
args->Set(TRI_V8_ASCII_STRING2(context->_isolate, "upgrade"),
|
||||
v8::Boolean::New(context->_isolate, _upgrade));
|
||||
|
||||
args->Set(TRI_V8_ASCII_STRING2(context->_isolate, "password"),
|
||||
TRI_V8_STD_STRING2(context->_isolate, defaultPassword));
|
||||
|
||||
localContext->Global()->Set(
|
||||
TRI_V8_ASCII_STRING2(context->_isolate, "UPGRADE_ARGS"), args);
|
||||
|
|
|
@ -41,8 +41,7 @@ class UpgradeFeature final : public application_features::ApplicationFeature {
|
|||
bool _upgradeCheck;
|
||||
|
||||
private:
|
||||
void changeAdminPassword(std::string const& defaultPassword);
|
||||
void upgradeDatabase(std::string const& defaultPassword);
|
||||
void upgradeDatabase();
|
||||
|
||||
private:
|
||||
int* _result;
|
||||
|
|
|
@ -1026,7 +1026,8 @@ static void JS_DropVocbaseCol(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
}
|
||||
}
|
||||
|
||||
if (auth->isActive()) {
|
||||
if (auth->isActive() && (ServerState::instance()->isCoordinator() ||
|
||||
!ServerState::instance()->isRunningInCluster())) {
|
||||
auth->authInfo()->enumerateUsers([&](AuthUserEntry& entry) {
|
||||
entry.removeCollection(dbname, collName);
|
||||
});
|
||||
|
@ -2766,17 +2767,6 @@ static void JS_TruncateVocbaseCol(
|
|||
TRI_V8_THROW_EXCEPTION_INTERNAL("cannot extract collection");
|
||||
}
|
||||
|
||||
AuthenticationFeature* auth = FeatureCacheFeature::instance()->authenticationFeature();
|
||||
if (auth->isActive() && ExecContext::CURRENT != nullptr) {
|
||||
CollectionNameResolver resolver(collection->vocbase());
|
||||
std::string const cName = resolver.getCollectionNameCluster(collection->cid());
|
||||
AuthLevel level = auth->canUseCollection(ExecContext::CURRENT->user(),
|
||||
collection->vocbase()->name(), cName);
|
||||
if (level != AuthLevel::RW) {
|
||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_FORBIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
// optionally specify non trx remove
|
||||
bool unsafeTruncate = false;
|
||||
if (args.Length() > 0) {
|
||||
|
|
|
@ -304,8 +304,11 @@ static void CreateVocBase(v8::FunctionCallbackInfo<v8::Value> const& args,
|
|||
if (result.IsEmpty()) {
|
||||
TRI_V8_THROW_EXCEPTION_MEMORY();
|
||||
}
|
||||
|
||||
// in case of success we grant the creating user RW access
|
||||
if (auth->isActive() && ExecContext::CURRENT != nullptr) {
|
||||
if (auth->isActive() && ExecContext::CURRENT != nullptr &&
|
||||
(ServerState::instance()->isCoordinator() ||
|
||||
!ServerState::instance()->isRunningInCluster())) {
|
||||
// this should not fail, we can not get here without database RW access
|
||||
auth->authInfo()->updateUser(ExecContext::CURRENT->user(),
|
||||
[&](AuthUserEntry& entry) {
|
||||
|
|
|
@ -229,18 +229,21 @@ void AuthInfo::loadFromDB() {
|
|||
|
||||
MUTEX_LOCKER(locker, _loadFromDBLock);
|
||||
|
||||
// double check to be sure after we got the lock
|
||||
if (!_outdated) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto role = ServerState::instance()->getRole();
|
||||
|
||||
if (role != ServerState::ROLE_SINGLE &&
|
||||
role != ServerState::ROLE_COORDINATOR) {
|
||||
TRI_ASSERT(false);
|
||||
_outdated = false;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
if (_authInfo.empty()) {// should only work once
|
||||
WRITE_LOCKER(writeLocker, _authInfoLock);
|
||||
insertInitial();
|
||||
}
|
||||
|
@ -252,15 +255,16 @@ void AuthInfo::loadFromDB() {
|
|||
|
||||
if (builder) {
|
||||
VPackSlice usersSlice = builder->slice();
|
||||
if (usersSlice.length() == 0) {
|
||||
insertInitial();
|
||||
} else {
|
||||
if (usersSlice.length() != 0) {
|
||||
parseUsers(usersSlice);
|
||||
}
|
||||
_outdated = false;
|
||||
} else {
|
||||
}
|
||||
|
||||
if (_authInfo.empty()) {
|
||||
insertInitial();
|
||||
}
|
||||
|
||||
_outdated = false;
|
||||
}
|
||||
|
||||
// private, must be called with _authInfoLock in write mode
|
||||
|
@ -461,6 +465,7 @@ static Result UpdateUser(VPackSlice const& user) {
|
|||
|
||||
Result AuthInfo::enumerateUsers(
|
||||
std::function<void(AuthUserEntry&)> const& func) {
|
||||
loadFromDB();
|
||||
// we require an consisten view on the user object
|
||||
{
|
||||
WRITE_LOCKER(guard, _authInfoLock);
|
||||
|
@ -484,6 +489,7 @@ Result AuthInfo::updateUser(std::string const& user,
|
|||
if (user.empty()) {
|
||||
return TRI_ERROR_USER_NOT_FOUND;
|
||||
}
|
||||
loadFromDB();
|
||||
VPackBuilder data;
|
||||
{ // we require an consisten view on the user object
|
||||
WRITE_LOCKER(guard, _authInfoLock);
|
||||
|
@ -506,6 +512,7 @@ Result AuthInfo::updateUser(std::string const& user,
|
|||
|
||||
Result AuthInfo::accessUser(std::string const& user,
|
||||
std::function<void(AuthUserEntry const&)> const& func) {
|
||||
loadFromDB();
|
||||
READ_LOCKER(guard, _authInfoLock);
|
||||
auto it = _authInfo.find(user);
|
||||
if (it != _authInfo.end()) {
|
||||
|
@ -516,6 +523,7 @@ Result AuthInfo::accessUser(std::string const& user,
|
|||
}
|
||||
|
||||
VPackBuilder AuthInfo::serializeUser(std::string const& user) {
|
||||
loadFromDB();
|
||||
VPackBuilder doc = QueryUser(_queryRegistry, user);
|
||||
VPackBuilder result;
|
||||
if (!doc.isEmpty()) {
|
||||
|
@ -524,6 +532,42 @@ VPackBuilder AuthInfo::serializeUser(std::string const& user) {
|
|||
return result;
|
||||
}
|
||||
|
||||
static Result removeUserInternal(AuthUserEntry const& entry) {
|
||||
TRI_ASSERT(!entry.key().empty());
|
||||
TRI_vocbase_t* vocbase = DatabaseFeature::DATABASE->systemDatabase();
|
||||
if (vocbase == nullptr) {
|
||||
return Result(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
// we cannot set this execution context, otherwise the transaction
|
||||
// will ask us again for permissions and we get a deadlock
|
||||
ExecContext* oldExe = ExecContext::CURRENT;
|
||||
ExecContext::CURRENT = nullptr;
|
||||
TRI_DEFER(ExecContext::CURRENT = oldExe);
|
||||
|
||||
std::shared_ptr<transaction::Context> ctx(
|
||||
new transaction::StandaloneContext(vocbase));
|
||||
SingleCollectionTransaction trx(ctx, TRI_COL_NAME_USERS,
|
||||
AccessMode::Type::WRITE);
|
||||
|
||||
trx.addHint(transaction::Hints::Hint::SINGLE_OPERATION);
|
||||
|
||||
Result res = trx.begin();
|
||||
if (res.ok()) {
|
||||
VPackBuilder builder;
|
||||
{
|
||||
VPackObjectBuilder guard(&builder);
|
||||
builder.add(StaticStrings::KeyString, VPackValue(entry.key()));
|
||||
// TODO maybe protect with a revision ID?
|
||||
}
|
||||
|
||||
OperationResult result =
|
||||
trx.remove(TRI_COL_NAME_USERS, builder.slice(), OperationOptions());
|
||||
res = trx.finish(result.code);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Result AuthInfo::removeUser(std::string const& user) {
|
||||
if (user.empty()) {
|
||||
return TRI_ERROR_USER_NOT_FOUND;
|
||||
|
@ -534,57 +578,51 @@ Result AuthInfo::removeUser(std::string const& user) {
|
|||
loadFromDB();
|
||||
|
||||
WRITE_LOCKER(guard, _authInfoLock);
|
||||
auto it = _authInfo.find(user);
|
||||
auto const& it = _authInfo.find(user);
|
||||
if (it == _authInfo.end()) {
|
||||
return Result(TRI_ERROR_USER_NOT_FOUND);
|
||||
return TRI_ERROR_USER_NOT_FOUND;
|
||||
}
|
||||
TRI_ASSERT(!it->second.key().empty());
|
||||
|
||||
TRI_vocbase_t* vocbase = DatabaseFeature::DATABASE->systemDatabase();
|
||||
if (vocbase == nullptr) {
|
||||
return Result(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
||||
// we cannot set this execution context, otherwise the transaction
|
||||
// will ask us again for permissions and we get a deadlock
|
||||
ExecContext* oldExe = ExecContext::CURRENT;
|
||||
ExecContext::CURRENT = nullptr;
|
||||
TRI_DEFER(ExecContext::CURRENT = oldExe);
|
||||
|
||||
std::shared_ptr<transaction::Context> ctx(
|
||||
new transaction::StandaloneContext(vocbase));
|
||||
SingleCollectionTransaction trx(ctx, TRI_COL_NAME_USERS,
|
||||
AccessMode::Type::WRITE);
|
||||
|
||||
trx.addHint(transaction::Hints::Hint::SINGLE_OPERATION);
|
||||
|
||||
Result res = trx.begin();
|
||||
|
||||
Result res = removeUserInternal(it->second);
|
||||
if (res.ok()) {
|
||||
VPackBuilder builder;
|
||||
{
|
||||
VPackObjectBuilder guard(&builder);
|
||||
builder.add(StaticStrings::KeyString, VPackValue(it->second.key()));
|
||||
// TODO maybe protect with a revision ID?
|
||||
}
|
||||
|
||||
OperationResult result =
|
||||
trx.remove(TRI_COL_NAME_USERS, builder.slice(), OperationOptions());
|
||||
res = trx.finish(result.code);
|
||||
if (res.ok()) {
|
||||
_authInfo.erase(it);
|
||||
reloadAllUsers();
|
||||
}
|
||||
_authInfo.erase(it);
|
||||
reloadAllUsers();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Result AuthInfo::removeAllUsers() {
|
||||
loadFromDB();
|
||||
|
||||
WRITE_LOCKER(guard, _authInfoLock);
|
||||
Result res;
|
||||
for (auto const& pair : _authInfo) {
|
||||
res = removeUserInternal(pair.second);
|
||||
if (!res.ok()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{// do not get into race conditions with loadFromDB
|
||||
MUTEX_LOCKER(locker, _loadFromDBLock);
|
||||
_authInfo.clear();
|
||||
_outdated = true;
|
||||
}
|
||||
reloadAllUsers();
|
||||
return res;
|
||||
}
|
||||
|
||||
VPackBuilder AuthInfo::getConfigData(std::string const& username) {
|
||||
loadFromDB();
|
||||
VPackBuilder bb = QueryUser(_queryRegistry, username);
|
||||
return VPackBuilder(bb.slice().get("configData"));
|
||||
}
|
||||
|
||||
Result AuthInfo::setConfigData(std::string const& user,
|
||||
velocypack::Slice const& data) {
|
||||
loadFromDB();
|
||||
|
||||
READ_LOCKER(guard, _authInfoLock);
|
||||
auto it = _authInfo.find(user);
|
||||
if (it == _authInfo.end()) {
|
||||
return Result(TRI_ERROR_USER_NOT_FOUND);
|
||||
|
@ -601,12 +639,16 @@ Result AuthInfo::setConfigData(std::string const& user,
|
|||
}
|
||||
|
||||
VPackBuilder AuthInfo::getUserData(std::string const& username) {
|
||||
loadFromDB();
|
||||
VPackBuilder bb = QueryUser(_queryRegistry, username);
|
||||
return VPackBuilder(bb.slice().get("userData"));
|
||||
}
|
||||
|
||||
Result AuthInfo::setUserData(std::string const& user,
|
||||
velocypack::Slice const& data) {
|
||||
loadFromDB();
|
||||
|
||||
READ_LOCKER(guard, _authInfoLock);
|
||||
auto it = _authInfo.find(user);
|
||||
if (it == _authInfo.end()) {
|
||||
return Result(TRI_ERROR_USER_NOT_FOUND);
|
||||
|
@ -702,8 +744,6 @@ AuthLevel AuthInfo::canUseCollection(std::string const& username,
|
|||
// public called from HttpCommTask.cpp and VstCommTask.cpp
|
||||
AuthResult AuthInfo::checkAuthentication(AuthenticationMethod authType,
|
||||
std::string const& secret) {
|
||||
loadFromDB();
|
||||
|
||||
switch (authType) {
|
||||
case AuthenticationMethod::BASIC:
|
||||
return checkAuthenticationBasic(secret);
|
||||
|
@ -718,10 +758,15 @@ AuthResult AuthInfo::checkAuthentication(AuthenticationMethod authType,
|
|||
|
||||
// private
|
||||
AuthResult AuthInfo::checkAuthenticationBasic(std::string const& secret) {
|
||||
auto role = ServerState::instance()->getRole();
|
||||
if (role != ServerState::ROLE_SINGLE &&
|
||||
role != ServerState::ROLE_COORDINATOR) {
|
||||
return AuthResult();
|
||||
}
|
||||
|
||||
{
|
||||
READ_LOCKER(guard, _authInfoLock);
|
||||
auto const& it = _authBasicCache.find(secret);
|
||||
|
||||
if (it != _authBasicCache.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
@ -729,9 +774,8 @@ AuthResult AuthInfo::checkAuthenticationBasic(std::string const& secret) {
|
|||
|
||||
std::string const up = StringUtils::decodeBase64(secret);
|
||||
std::string::size_type n = up.find(':', 0);
|
||||
|
||||
if (n == std::string::npos || n == 0 || n + 1 > up.size()) {
|
||||
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
|
||||
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
|
||||
<< "invalid authentication data found, cannot extract "
|
||||
"username/password";
|
||||
return AuthResult();
|
||||
|
@ -741,7 +785,6 @@ AuthResult AuthInfo::checkAuthenticationBasic(std::string const& secret) {
|
|||
std::string password = up.substr(n + 1);
|
||||
|
||||
AuthResult result = checkPassword(username, password);
|
||||
|
||||
{
|
||||
WRITE_LOCKER(guard, _authInfoLock);
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ class AuthInfo {
|
|||
std::function<void(AuthUserEntry const&)> const&);
|
||||
velocypack::Builder serializeUser(std::string const& user);
|
||||
Result removeUser(std::string const& user);
|
||||
Result removeAllUsers();
|
||||
|
||||
velocypack::Builder getConfigData(std::string const& user);
|
||||
Result setConfigData(std::string const& user, velocypack::Slice const& data);
|
||||
|
|
|
@ -463,7 +463,8 @@ arangodb::Result Databases::drop(TRI_vocbase_t* systemVocbase,
|
|||
}
|
||||
|
||||
auto auth = FeatureCacheFeature::instance()->authenticationFeature();
|
||||
if (auth->isActive()) {
|
||||
if (auth->isActive() && (ServerState::instance()->isCoordinator() ||
|
||||
!ServerState::instance()->isRunningInCluster())) {
|
||||
auth->authInfo()->enumerateUsers(
|
||||
[&](AuthUserEntry& entry) { entry.removeDatabase(dbName); });
|
||||
}
|
||||
|
|
|
@ -462,8 +462,10 @@ void ImportFeature::start() {
|
|||
}
|
||||
|
||||
} else {
|
||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error message: "
|
||||
<< ih.getErrorMessage();
|
||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error message:";
|
||||
for (std::string const& msg : ih.getErrorMessages()) {
|
||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << msg;
|
||||
}
|
||||
}
|
||||
} catch (std::exception const& ex) {
|
||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Caught exception " << ex.what()
|
||||
|
|
|
@ -173,7 +173,7 @@ ImportHelper::ImportHelper(ClientFeature const* client,
|
|||
while (true) {
|
||||
uint32_t numReady = 0;
|
||||
for (auto const& t : _senderThreads) {
|
||||
if (t->isReady()) {
|
||||
if (t->isIdle()) {
|
||||
numReady++;
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ bool ImportHelper::importDelimited(std::string const& collectionName,
|
|||
_firstLine = "";
|
||||
_outputBuffer.clear();
|
||||
_lineBuffer.clear();
|
||||
_errorMessage = "";
|
||||
_errorMessages.clear();
|
||||
_hasError = false;
|
||||
|
||||
// read and convert
|
||||
|
@ -217,7 +217,7 @@ bool ImportHelper::importDelimited(std::string const& collectionName,
|
|||
fd = TRI_TRACKED_OPEN_FILE(fileName.c_str(), O_RDONLY | TRI_O_CLOEXEC);
|
||||
|
||||
if (fd < 0) {
|
||||
_errorMessage = TRI_LAST_ERROR_STR;
|
||||
_errorMessages.push_back(TRI_LAST_ERROR_STR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -235,8 +235,7 @@ bool ImportHelper::importDelimited(std::string const& collectionName,
|
|||
if (fd != STDIN_FILENO) {
|
||||
TRI_TRACKED_CLOSE_FILE(fd);
|
||||
}
|
||||
|
||||
_errorMessage = "out of memory";
|
||||
_errorMessages.push_back("out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -270,7 +269,7 @@ bool ImportHelper::importDelimited(std::string const& collectionName,
|
|||
if (fd != STDIN_FILENO) {
|
||||
TRI_TRACKED_CLOSE_FILE(fd);
|
||||
}
|
||||
_errorMessage = TRI_LAST_ERROR_STR;
|
||||
_errorMessages.push_back(TRI_LAST_ERROR_STR);
|
||||
return false;
|
||||
} else if (n == 0) {
|
||||
// we have read the entire file
|
||||
|
@ -311,7 +310,7 @@ bool ImportHelper::importJson(std::string const& collectionName,
|
|||
_collectionName = collectionName;
|
||||
_firstLine = "";
|
||||
_outputBuffer.clear();
|
||||
_errorMessage = "";
|
||||
_errorMessages.clear();
|
||||
_hasError = false;
|
||||
|
||||
// read and convert
|
||||
|
@ -328,7 +327,7 @@ bool ImportHelper::importJson(std::string const& collectionName,
|
|||
fd = TRI_TRACKED_OPEN_FILE(fileName.c_str(), O_RDONLY | TRI_O_CLOEXEC);
|
||||
|
||||
if (fd < 0) {
|
||||
_errorMessage = TRI_LAST_ERROR_STR;
|
||||
_errorMessages.push_back(TRI_LAST_ERROR_STR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +349,7 @@ bool ImportHelper::importJson(std::string const& collectionName,
|
|||
while (!_hasError) {
|
||||
// reserve enough room to read more data
|
||||
if (_outputBuffer.reserve(BUFFER_SIZE) == TRI_ERROR_OUT_OF_MEMORY) {
|
||||
_errorMessage = TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY);
|
||||
_errorMessages.push_back(TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY));
|
||||
|
||||
if (fd != STDIN_FILENO) {
|
||||
TRI_TRACKED_CLOSE_FILE(fd);
|
||||
|
@ -362,7 +361,7 @@ bool ImportHelper::importJson(std::string const& collectionName,
|
|||
ssize_t n = TRI_READ(fd, _outputBuffer.end(), BUFFER_SIZE - 1);
|
||||
|
||||
if (n < 0) {
|
||||
_errorMessage = TRI_LAST_ERROR_STR;
|
||||
_errorMessages.push_back(TRI_LAST_ERROR_STR);
|
||||
if (fd != STDIN_FILENO) {
|
||||
TRI_TRACKED_CLOSE_FILE(fd);
|
||||
}
|
||||
|
@ -398,10 +397,9 @@ bool ImportHelper::importJson(std::string const& collectionName,
|
|||
if (fd != STDIN_FILENO) {
|
||||
TRI_TRACKED_CLOSE_FILE(fd);
|
||||
}
|
||||
_errorMessage =
|
||||
"import file is too big. please increase the value of --batch-size "
|
||||
"(currently " +
|
||||
StringUtils::itoa(_maxUploadSize) + ")";
|
||||
_errorMessages.push_back("import file is too big. please increase the value of --batch-size "
|
||||
"(currently " +
|
||||
StringUtils::itoa(_maxUploadSize) + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -750,7 +748,7 @@ bool ImportHelper::truncateCollection() {
|
|||
<< "unable to truncate collection '" << _collectionName
|
||||
<< "', server returned status code: " << static_cast<int>(code);
|
||||
_hasError = true;
|
||||
_errorMessage = "Unable to overwrite collection";
|
||||
_errorMessages.push_back("Unable to overwrite collection");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -832,7 +830,7 @@ SenderThread* ImportHelper::findSender() {
|
|||
for (auto const& t : _senderThreads) {
|
||||
if (t->hasError()) {
|
||||
_hasError = true;
|
||||
_errorMessage = t->errorMessage();
|
||||
_errorMessages.push_back(t->errorMessage());
|
||||
return nullptr;
|
||||
} else if (t->isIdle()) {
|
||||
return t.get();
|
||||
|
|
|
@ -233,7 +233,7 @@ class ImportHelper {
|
|||
/// @return string get the error message
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string getErrorMessage() { return _errorMessage; }
|
||||
std::vector<std::string> getErrorMessages() { return _errorMessages; }
|
||||
|
||||
private:
|
||||
static void ProcessCsvBegin(TRI_csv_parser_t*, size_t);
|
||||
|
@ -293,7 +293,7 @@ class ImportHelper {
|
|||
std::unordered_map<std::string, std::string> _translations;
|
||||
|
||||
bool _hasError;
|
||||
std::string _errorMessage;
|
||||
std::vector<std::string> _errorMessages;
|
||||
|
||||
static double const ProgressStep;
|
||||
};
|
||||
|
|
|
@ -58,7 +58,9 @@ class SenderThread : public arangodb::Thread {
|
|||
void sendData(std::string const& url, basics::StringBuffer* sender);
|
||||
|
||||
bool hasError();
|
||||
/// Ready to start sending
|
||||
bool isReady();
|
||||
/// Currently not sending data
|
||||
bool isIdle();
|
||||
bool isDone();
|
||||
|
||||
|
|
|
@ -982,8 +982,12 @@ static void ClientConnection_importCsv(
|
|||
TRI_V8_RETURN(result);
|
||||
}
|
||||
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED,
|
||||
ih.getErrorMessage().c_str());
|
||||
std::string error = "error messages:";
|
||||
for (std::string const& msg : ih.getErrorMessages()) {
|
||||
error.append(msg + ";\t");
|
||||
}
|
||||
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED, error.c_str());
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
|
@ -1046,9 +1050,13 @@ static void ClientConnection_importJson(
|
|||
|
||||
TRI_V8_RETURN(result);
|
||||
}
|
||||
|
||||
std::string error = "error messages:";
|
||||
for (std::string const& msg : ih.getErrorMessages()) {
|
||||
error.append(msg + ";\t");
|
||||
}
|
||||
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED,
|
||||
ih.getErrorMessage().c_str());
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED, error.c_str());
|
||||
TRI_V8_TRY_CATCH_END
|
||||
}
|
||||
|
||||
|
|
|
@ -971,6 +971,7 @@ function startInstanceCluster (instanceInfo, protocol, options,
|
|||
throw new Error("startup timed out!");
|
||||
}
|
||||
}
|
||||
|
||||
arango.reconnect(instanceInfo.endpoint, '_system', 'root', '');
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/*jshint -W051:true, -W069:true */
|
||||
'use strict';
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2016 ArangoDB 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 Frank Celler
|
||||
/// @author Copyright 2016, ArangoDB GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
(function() {
|
||||
var args = global.UPGRADE_ARGS;
|
||||
delete global.UPGRADE_ARGS;
|
||||
|
||||
require("internal").db._users.truncate();
|
||||
|
||||
const users = require("@arangodb/users");
|
||||
|
||||
users.save("root", args.password, true);
|
||||
users.grantDatabase("root", "*", "rw");
|
||||
}());
|
|
@ -44,9 +44,7 @@
|
|||
const db = internal.db;
|
||||
const shallowCopy = require('@arangodb/util').shallowCopy;
|
||||
|
||||
const defaultRootPW = args.password || '';
|
||||
|
||||
function upgrade () {
|
||||
function upgrade () {
|
||||
|
||||
// default replication factor for system collections
|
||||
const DEFAULT_REPLICATION_FACTOR_SYSTEM = internal.DEFAULT_REPLICATION_FACTOR_SYSTEM;
|
||||
|
|
Loading…
Reference in New Issue