mirror of https://gitee.com/bigwinds/arangodb
forward port branch feature-3.3/allow-jwt-in-arangosh (#5009)
This commit is contained in:
parent
167dfcdf7f
commit
8b9eb13925
|
@ -66,7 +66,8 @@ auth::TokenCache::~TokenCache() {
|
||||||
|
|
||||||
void auth::TokenCache::setJwtSecret(std::string const& jwtSecret) {
|
void auth::TokenCache::setJwtSecret(std::string const& jwtSecret) {
|
||||||
WRITE_LOCKER(writeLocker, _jwtLock);
|
WRITE_LOCKER(writeLocker, _jwtLock);
|
||||||
LOG_TOPIC(DEBUG, Logger::AUTHENTICATION) << "Setting jwt secret " << jwtSecret;
|
LOG_TOPIC(DEBUG, Logger::AUTHENTICATION)
|
||||||
|
<< "Setting jwt secret " << jwtSecret;
|
||||||
_jwtSecret = jwtSecret;
|
_jwtSecret = jwtSecret;
|
||||||
_jwtCache.clear();
|
_jwtCache.clear();
|
||||||
generateJwtToken();
|
generateJwtToken();
|
||||||
|
@ -171,7 +172,7 @@ auth::TokenCache::Entry auth::TokenCache::checkAuthenticationJWT(
|
||||||
_jwtCache.remove(jwt);
|
_jwtCache.remove(jwt);
|
||||||
} catch (std::range_error const&) {
|
} catch (std::range_error const&) {
|
||||||
}
|
}
|
||||||
LOG_TOPIC(TRACE, Logger::AUTHENTICATION) << "JWT Token expired";
|
LOG_TOPIC(TRACE, Logger::AUTHENTICATION) << "JWT Token expired";
|
||||||
return auth::TokenCache::Entry(); // unauthorized
|
return auth::TokenCache::Entry(); // unauthorized
|
||||||
}
|
}
|
||||||
// LDAP rights might need to be refreshed
|
// LDAP rights might need to be refreshed
|
||||||
|
@ -180,11 +181,11 @@ auth::TokenCache::Entry auth::TokenCache::checkAuthenticationJWT(
|
||||||
} catch (std::range_error const&) {
|
} catch (std::range_error const&) {
|
||||||
// mop: not found
|
// mop: not found
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> const parts = StringUtils::split(jwt, '.');
|
std::vector<std::string> const parts = StringUtils::split(jwt, '.');
|
||||||
if (parts.size() != 3) {
|
if (parts.size() != 3) {
|
||||||
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "Secret contains "
|
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
|
||||||
<< parts.size() << " parts";
|
<< "Secret contains " << parts.size() << " parts";
|
||||||
return auth::TokenCache::Entry();
|
return auth::TokenCache::Entry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,8 +209,8 @@ auth::TokenCache::Entry auth::TokenCache::checkAuthenticationJWT(
|
||||||
std::string const message = header + "." + body;
|
std::string const message = header + "." + body;
|
||||||
if (!validateJwtHMAC256Signature(message, signature)) {
|
if (!validateJwtHMAC256Signature(message, signature)) {
|
||||||
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
|
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
|
||||||
<< "Couldn't validate jwt signature " << signature
|
<< "Couldn't validate jwt signature " << signature << " against "
|
||||||
<< " against " << _jwtSecret;
|
<< _jwtSecret;
|
||||||
return auth::TokenCache::Entry();
|
return auth::TokenCache::Entry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,11 +227,11 @@ std::shared_ptr<VPackBuilder> auth::TokenCache::parseJson(
|
||||||
parser.parse(str);
|
parser.parse(str);
|
||||||
result = parser.steal();
|
result = parser.steal();
|
||||||
} catch (std::bad_alloc const&) {
|
} catch (std::bad_alloc const&) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Out of memory parsing " << hint
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
<< "!";
|
<< "Out of memory parsing " << hint << "!";
|
||||||
} catch (VPackException const& ex) {
|
} catch (VPackException const& ex) {
|
||||||
LOG_TOPIC(DEBUG, arangodb::Logger::FIXME) << "Couldn't parse " << hint
|
LOG_TOPIC(DEBUG, arangodb::Logger::FIXME)
|
||||||
<< ": " << ex.what();
|
<< "Couldn't parse " << hint << ": " << ex.what();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
<< "Got unknown exception trying to parse " << hint;
|
<< "Got unknown exception trying to parse " << hint;
|
||||||
|
@ -292,14 +293,12 @@ auth::TokenCache::Entry auth::TokenCache::validateJwtBody(
|
||||||
|
|
||||||
VPackSlice const issSlice = bodySlice.get("iss");
|
VPackSlice const issSlice = bodySlice.get("iss");
|
||||||
if (!issSlice.isString()) {
|
if (!issSlice.isString()) {
|
||||||
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
|
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION) << "missing iss value";
|
||||||
<< "missing iss value";
|
|
||||||
return authResult; // unauthenticated
|
return authResult; // unauthenticated
|
||||||
}
|
}
|
||||||
|
|
||||||
if (issSlice.copyString() != "arangodb") {
|
if (issSlice.copyString() != "arangodb") {
|
||||||
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
|
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION) << "invalid iss value";
|
||||||
<< "invalid iss value";
|
|
||||||
return authResult; // unauthenticated
|
return authResult; // unauthenticated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +313,7 @@ auth::TokenCache::Entry auth::TokenCache::validateJwtBody(
|
||||||
// authResult._username = "root";
|
// authResult._username = "root";
|
||||||
} else {
|
} else {
|
||||||
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
|
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
|
||||||
<< "Lacking preferred_username or server_id";
|
<< "Lacking preferred_username or server_id";
|
||||||
return authResult; // unauthenticated
|
return authResult; // unauthenticated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +362,8 @@ std::string auth::TokenCache::generateRawJwt(VPackSlice const& body) const {
|
||||||
std::string fullMessage(StringUtils::encodeBase64(headerBuilder.toJson()) +
|
std::string fullMessage(StringUtils::encodeBase64(headerBuilder.toJson()) +
|
||||||
"." + StringUtils::encodeBase64(body.toJson()));
|
"." + StringUtils::encodeBase64(body.toJson()));
|
||||||
if (_jwtSecret.empty()) {
|
if (_jwtSecret.empty()) {
|
||||||
LOG_TOPIC(INFO, Logger::AUTHENTICATION) << "Using cluster without JWT Token";
|
LOG_TOPIC(INFO, Logger::AUTHENTICATION)
|
||||||
|
<< "Using cluster without JWT Token";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string signature =
|
std::string signature =
|
||||||
|
|
|
@ -23,13 +23,13 @@
|
||||||
#include "AuthenticationFeature.h"
|
#include "AuthenticationFeature.h"
|
||||||
|
|
||||||
#include "ApplicationFeatures/ApplicationServer.h"
|
#include "ApplicationFeatures/ApplicationServer.h"
|
||||||
|
#include "Auth/Common.h"
|
||||||
#include "Auth/Handler.h"
|
#include "Auth/Handler.h"
|
||||||
#include "Cluster/ServerState.h"
|
#include "Cluster/ServerState.h"
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
#include "ProgramOptions/ProgramOptions.h"
|
#include "ProgramOptions/ProgramOptions.h"
|
||||||
#include "Random/RandomGenerator.h"
|
#include "Random/RandomGenerator.h"
|
||||||
#include "RestServer/QueryRegistryFeature.h"
|
#include "RestServer/QueryRegistryFeature.h"
|
||||||
#include "Auth/Common.h"
|
|
||||||
|
|
||||||
#if USE_ENTERPRISE
|
#if USE_ENTERPRISE
|
||||||
#include "Enterprise/Ldap/LdapAuthenticationHandler.h"
|
#include "Enterprise/Ldap/LdapAuthenticationHandler.h"
|
||||||
|
@ -87,13 +87,15 @@ void AuthenticationFeature::collectOptions(
|
||||||
"enable or disable authentication for ALL client requests",
|
"enable or disable authentication for ALL client requests",
|
||||||
new BooleanParameter(&_active));
|
new BooleanParameter(&_active));
|
||||||
|
|
||||||
options->addOption("--server.authentication-timeout",
|
options->addOption(
|
||||||
"timeout for the authentication cache in seconds (0 = indefinitely)",
|
"--server.authentication-timeout",
|
||||||
new DoubleParameter(&_authenticationTimeout));
|
"timeout for the authentication cache in seconds (0 = indefinitely)",
|
||||||
|
new DoubleParameter(&_authenticationTimeout));
|
||||||
|
|
||||||
options->addOption("--server.local-authentication",
|
options->addOption(
|
||||||
"enable or disable authentication using the local user database",
|
"--server.local-authentication",
|
||||||
new BooleanParameter(&_localAuthentication));
|
"enable or disable authentication using the local user database",
|
||||||
|
new BooleanParameter(&_localAuthentication));
|
||||||
|
|
||||||
options->addOption(
|
options->addOption(
|
||||||
"--server.authentication-system-only",
|
"--server.authentication-system-only",
|
||||||
|
@ -123,30 +125,33 @@ void AuthenticationFeature::validateOptions(std::shared_ptr<ProgramOptions>) {
|
||||||
|
|
||||||
void AuthenticationFeature::prepare() {
|
void AuthenticationFeature::prepare() {
|
||||||
TRI_ASSERT(isEnabled());
|
TRI_ASSERT(isEnabled());
|
||||||
TRI_ASSERT(_userManager == nullptr);
|
TRI_ASSERT(_userManager == nullptr);
|
||||||
#if USE_ENTERPRISE
|
#if USE_ENTERPRISE
|
||||||
if (application_features::ApplicationServer::getFeature<LdapFeature>("Ldap")
|
if (application_features::ApplicationServer::getFeature<LdapFeature>("Ldap")
|
||||||
->isEnabled()) {
|
->isEnabled()) {
|
||||||
_userManager = new auth::UserManager(std::make_unique<LdapAuthenticationHandler>());
|
_userManager =
|
||||||
} else {
|
new auth::UserManager(std::make_unique<LdapAuthenticationHandler>());
|
||||||
_userManager = new auth::UserManager();
|
} else {
|
||||||
}
|
|
||||||
#else
|
|
||||||
_userManager = new auth::UserManager();
|
_userManager = new auth::UserManager();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
_userManager = new auth::UserManager();
|
||||||
#endif
|
#endif
|
||||||
TRI_ASSERT(_authCache == nullptr);
|
TRI_ASSERT(_authCache == nullptr);
|
||||||
_authCache = new auth::TokenCache(_userManager, _authenticationTimeout);
|
_authCache = new auth::TokenCache(_userManager, _authenticationTimeout);
|
||||||
|
|
||||||
std::string jwtSecret = _jwtSecretProgramOption;
|
std::string jwtSecret = _jwtSecretProgramOption;
|
||||||
|
|
||||||
if (jwtSecret.empty()) {
|
if (jwtSecret.empty()) {
|
||||||
LOG_TOPIC(INFO, Logger::AUTHENTICATION) << "Jwt secret not specified, generating...";
|
LOG_TOPIC(INFO, Logger::AUTHENTICATION)
|
||||||
|
<< "Jwt secret not specified, generating...";
|
||||||
uint16_t m = 254;
|
uint16_t m = 254;
|
||||||
for (size_t i = 0; i < _maxSecretLength; i++) {
|
for (size_t i = 0; i < _maxSecretLength; i++) {
|
||||||
jwtSecret += (1 + RandomGenerator::interval(m));
|
jwtSecret += (1 + RandomGenerator::interval(m));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_authCache->setJwtSecret(jwtSecret);
|
_authCache->setJwtSecret(jwtSecret);
|
||||||
|
|
||||||
INSTANCE = this;
|
INSTANCE = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,8 +163,8 @@ void AuthenticationFeature::start() {
|
||||||
out << "Authentication is turned " << (_active ? "on" : "off");
|
out << "Authentication is turned " << (_active ? "on" : "off");
|
||||||
|
|
||||||
auto queryRegistryFeature =
|
auto queryRegistryFeature =
|
||||||
application_features::ApplicationServer::getFeature<
|
application_features::ApplicationServer::getFeature<QueryRegistryFeature>(
|
||||||
QueryRegistryFeature>("QueryRegistry");
|
"QueryRegistry");
|
||||||
_userManager->setQueryRegistry(queryRegistryFeature->queryRegistry());
|
_userManager->setQueryRegistry(queryRegistryFeature->queryRegistry());
|
||||||
|
|
||||||
if (_active && _authenticationSystemOnly) {
|
if (_active && _authenticationSystemOnly) {
|
||||||
|
@ -167,12 +172,11 @@ void AuthenticationFeature::start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ARANGODB_HAVE_DOMAIN_SOCKETS
|
#ifdef ARANGODB_HAVE_DOMAIN_SOCKETS
|
||||||
out << ", authentication for unix sockets is turned "
|
out << ", authentication for unix sockets is turned "
|
||||||
<< (_authenticationUnixSockets ? "on" : "off");
|
<< (_authenticationUnixSockets ? "on" : "off");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LOG_TOPIC(INFO, arangodb::Logger::AUTHENTICATION) << out.str();
|
LOG_TOPIC(INFO, arangodb::Logger::AUTHENTICATION) << out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuthenticationFeature::unprepare() { INSTANCE = nullptr; }
|
void AuthenticationFeature::unprepare() { INSTANCE = nullptr; }
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ int main(int argc, char* argv[]) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
server.addFeature(new BenchFeature(&server, &ret));
|
server.addFeature(new BenchFeature(&server, &ret));
|
||||||
server.addFeature(new ClientFeature(&server));
|
server.addFeature(new ClientFeature(&server, false));
|
||||||
server.addFeature(new ConfigFeature(&server, "arangobench"));
|
server.addFeature(new ConfigFeature(&server, "arangobench"));
|
||||||
server.addFeature(new LoggerFeature(&server, false));
|
server.addFeature(new LoggerFeature(&server, false));
|
||||||
server.addFeature(new RandomFeature(&server));
|
server.addFeature(new RandomFeature(&server));
|
||||||
|
|
|
@ -58,7 +58,7 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
server.addFeature(new ClientFeature(&server));
|
server.addFeature(new ClientFeature(&server, false));
|
||||||
server.addFeature(new ConfigFeature(&server, "arangodump"));
|
server.addFeature(new ConfigFeature(&server, "arangodump"));
|
||||||
server.addFeature(new DumpFeature(&server, ret));
|
server.addFeature(new DumpFeature(&server, ret));
|
||||||
server.addFeature(new LoggerFeature(&server, false));
|
server.addFeature(new LoggerFeature(&server, false));
|
||||||
|
|
|
@ -53,7 +53,7 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
server.addFeature(new ClientFeature(&server));
|
server.addFeature(new ClientFeature(&server, false));
|
||||||
server.addFeature(new ConfigFeature(&server, "arangoexport"));
|
server.addFeature(new ConfigFeature(&server, "arangoexport"));
|
||||||
server.addFeature(new ExportFeature(&server, &ret));
|
server.addFeature(new ExportFeature(&server, &ret));
|
||||||
server.addFeature(new LoggerFeature(&server, false));
|
server.addFeature(new LoggerFeature(&server, false));
|
||||||
|
|
|
@ -53,7 +53,7 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
server.addFeature(new ClientFeature(&server));
|
server.addFeature(new ClientFeature(&server, false));
|
||||||
server.addFeature(new ConfigFeature(&server, "arangoimport"));
|
server.addFeature(new ConfigFeature(&server, "arangoimport"));
|
||||||
server.addFeature(new ImportFeature(&server, &ret));
|
server.addFeature(new ImportFeature(&server, &ret));
|
||||||
server.addFeature(new LoggerFeature(&server, false));
|
server.addFeature(new LoggerFeature(&server, false));
|
||||||
|
|
|
@ -58,7 +58,7 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
server.addFeature(new ClientFeature(&server));
|
server.addFeature(new ClientFeature(&server, false));
|
||||||
server.addFeature(new ConfigFeature(&server, "arangorestore"));
|
server.addFeature(new ConfigFeature(&server, "arangorestore"));
|
||||||
server.addFeature(new LoggerFeature(&server, false));
|
server.addFeature(new LoggerFeature(&server, false));
|
||||||
server.addFeature(new RandomFeature(&server));
|
server.addFeature(new RandomFeature(&server));
|
||||||
|
|
|
@ -42,21 +42,25 @@ using namespace arangodb::httpclient;
|
||||||
using namespace arangodb::options;
|
using namespace arangodb::options;
|
||||||
|
|
||||||
ClientFeature::ClientFeature(application_features::ApplicationServer* server,
|
ClientFeature::ClientFeature(application_features::ApplicationServer* server,
|
||||||
double connectionTimeout, double requestTimeout)
|
bool allowJwtSecret, double connectionTimeout,
|
||||||
|
double requestTimeout)
|
||||||
: ApplicationFeature(server, "Client"),
|
: ApplicationFeature(server, "Client"),
|
||||||
_databaseName("_system"),
|
_databaseName("_system"),
|
||||||
_authentication(true),
|
_authentication(true),
|
||||||
|
_askJwtSecret(false),
|
||||||
_endpoint(Endpoint::defaultEndpoint(Endpoint::TransportType::HTTP)),
|
_endpoint(Endpoint::defaultEndpoint(Endpoint::TransportType::HTTP)),
|
||||||
_username("root"),
|
_username("root"),
|
||||||
_password(""),
|
_password(""),
|
||||||
|
_jwtSecret(""),
|
||||||
_connectionTimeout(connectionTimeout),
|
_connectionTimeout(connectionTimeout),
|
||||||
_requestTimeout(requestTimeout),
|
_requestTimeout(requestTimeout),
|
||||||
_maxPacketSize(128 * 1024 * 1024),
|
_maxPacketSize(128 * 1024 * 1024),
|
||||||
_sslProtocol(TLS_V12),
|
_sslProtocol(TLS_V12),
|
||||||
|
_allowJwtSecret(allowJwtSecret),
|
||||||
_retries(DEFAULT_RETRIES),
|
_retries(DEFAULT_RETRIES),
|
||||||
_warn(false),
|
_warn(false),
|
||||||
_warnConnect(true),
|
_warnConnect(true),
|
||||||
_haveServerPassword(false){
|
_haveServerPassword(false) {
|
||||||
setOptional(true);
|
setOptional(true);
|
||||||
requiresElevatedPrivileges(false);
|
requiresElevatedPrivileges(false);
|
||||||
startsAfter("Logger");
|
startsAfter("Logger");
|
||||||
|
@ -70,11 +74,11 @@ void ClientFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
new StringParameter(&_databaseName));
|
new StringParameter(&_databaseName));
|
||||||
|
|
||||||
options->addOption("--server.authentication",
|
options->addOption("--server.authentication",
|
||||||
"require authentication credentials when connecting (does not affect the server-side authentication settings)",
|
"require authentication credentials when connecting (does "
|
||||||
|
"not affect the server-side authentication settings)",
|
||||||
new BooleanParameter(&_authentication));
|
new BooleanParameter(&_authentication));
|
||||||
|
|
||||||
options->addOption("--server.username",
|
options->addOption("--server.username", "username to use when connecting",
|
||||||
"username to use when connecting",
|
|
||||||
new StringParameter(&_username));
|
new StringParameter(&_username));
|
||||||
|
|
||||||
options->addOption(
|
options->addOption(
|
||||||
|
@ -88,23 +92,37 @@ void ClientFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
"for a password",
|
"for a password",
|
||||||
new StringParameter(&_password));
|
new StringParameter(&_password));
|
||||||
|
|
||||||
|
if (_allowJwtSecret) {
|
||||||
|
// currently the option is only present for arangosh, but none
|
||||||
|
// of the other client tools
|
||||||
|
options->addHiddenOption(
|
||||||
|
"--server.ask-jwt-secret",
|
||||||
|
"if this option is specified, the user will be prompted "
|
||||||
|
"for a JWT secret. This option is not compatible with "
|
||||||
|
"--server.username or --server.password. If specified, it will be used for all "
|
||||||
|
"connections - even when a new connection to another server is "
|
||||||
|
"created",
|
||||||
|
new BooleanParameter(&_askJwtSecret));
|
||||||
|
}
|
||||||
|
|
||||||
options->addOption("--server.connection-timeout",
|
options->addOption("--server.connection-timeout",
|
||||||
"connection timeout in seconds",
|
"connection timeout in seconds",
|
||||||
new DoubleParameter(&_connectionTimeout));
|
new DoubleParameter(&_connectionTimeout));
|
||||||
|
|
||||||
options->addOption("--server.request-timeout",
|
options->addOption("--server.request-timeout", "request timeout in seconds",
|
||||||
"request timeout in seconds",
|
|
||||||
new DoubleParameter(&_requestTimeout));
|
new DoubleParameter(&_requestTimeout));
|
||||||
|
|
||||||
options->addHiddenOption("--server.max-packet-size",
|
options->addHiddenOption(
|
||||||
"maximum packet size (in bytes) for client/server communication",
|
"--server.max-packet-size",
|
||||||
new UInt64Parameter(&_maxPacketSize));
|
"maximum packet size (in bytes) for client/server communication",
|
||||||
|
new UInt64Parameter(&_maxPacketSize));
|
||||||
|
|
||||||
std::unordered_set<uint64_t> sslProtocols = {1, 2, 3, 4, 5};
|
std::unordered_set<uint64_t> sslProtocols = {1, 2, 3, 4, 5};
|
||||||
|
|
||||||
options->addSection("ssl", "Configure SSL communication");
|
options->addSection("ssl", "Configure SSL communication");
|
||||||
options->addOption("--ssl.protocol",
|
options->addOption("--ssl.protocol",
|
||||||
"ssl protocol (1 = SSLv2, 2 = SSLv2 or SSLv3 (negotiated), 3 = SSLv3, 4 = "
|
"ssl protocol (1 = SSLv2, 2 = SSLv2 or SSLv3 "
|
||||||
|
"(negotiated), 3 = SSLv3, 4 = "
|
||||||
"TLSv1, 5 = TLSV1.2)",
|
"TLSv1, 5 = TLSV1.2)",
|
||||||
new DiscreteValuesParameter<UInt64Parameter>(
|
new DiscreteValuesParameter<UInt64Parameter>(
|
||||||
&_sslProtocol, sslProtocols));
|
&_sslProtocol, sslProtocols));
|
||||||
|
@ -116,6 +134,10 @@ void ClientFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
_authentication = true;
|
_authentication = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_askJwtSecret) {
|
||||||
|
_authentication = false;
|
||||||
|
}
|
||||||
|
|
||||||
// check timeouts
|
// check timeouts
|
||||||
if (_connectionTimeout < 0.0) {
|
if (_connectionTimeout < 0.0) {
|
||||||
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "invalid value for --server.connect-timeout, must be >= 0";
|
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "invalid value for --server.connect-timeout, must be >= 0";
|
||||||
|
@ -144,30 +166,70 @@ void ClientFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
|
|
||||||
_haveServerPassword = !options->processingResult().touched("server.password");
|
_haveServerPassword = !options->processingResult().touched("server.password");
|
||||||
|
|
||||||
|
if (_askJwtSecret && options->processingResult().touched("server.password")) {
|
||||||
|
LOG_TOPIC(FATAL, arangodb::Logger::FIXME)
|
||||||
|
<< "cannot specify both --server.password and --server.ask-jwt-token";
|
||||||
|
FATAL_ERROR_EXIT();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_askJwtSecret && options->processingResult().touched("server.username")) {
|
||||||
|
LOG_TOPIC(FATAL, arangodb::Logger::FIXME)
|
||||||
|
<< "cannot specify both --server.username and --server.ask-jwt-token";
|
||||||
|
FATAL_ERROR_EXIT();
|
||||||
|
}
|
||||||
|
|
||||||
SimpleHttpClientParams::setDefaultMaxPacketSize(_maxPacketSize);
|
SimpleHttpClientParams::setDefaultMaxPacketSize(_maxPacketSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientFeature::prepare() {
|
void ClientFeature::readPassword() {
|
||||||
// ask for a password
|
usleep(10 * 1000);
|
||||||
if (_authentication &&
|
|
||||||
isEnabled() &&
|
|
||||||
_haveServerPassword) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(10 * 1000));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ConsoleFeature* console =
|
ConsoleFeature* console =
|
||||||
ApplicationServer::getFeature<ConsoleFeature>("Console");
|
ApplicationServer::getFeature<ConsoleFeature>("Console");
|
||||||
|
|
||||||
if (console->isEnabled()) {
|
if (console->isEnabled()) {
|
||||||
_password = console->readPassword("Please specify a password: ");
|
_password = console->readPassword("Please specify a password: ");
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
} catch (...) {
|
|
||||||
}
|
}
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "Please specify a password: " << std::flush;
|
std::cout << "Please specify a password: " << std::flush;
|
||||||
_password = ConsoleFeature::readPassword();
|
_password = ConsoleFeature::readPassword();
|
||||||
std::cout << std::endl << std::flush;
|
std::cout << std::endl << std::flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientFeature::readJwtSecret() {
|
||||||
|
usleep(10 * 1000);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ConsoleFeature* console =
|
||||||
|
ApplicationServer::getFeature<ConsoleFeature>("Console");
|
||||||
|
|
||||||
|
if (console->isEnabled()) {
|
||||||
|
_jwtSecret = console->readPassword("Please specify the JWT secret: ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Please specify the JWT secret: " << std::flush;
|
||||||
|
_jwtSecret = ConsoleFeature::readPassword();
|
||||||
|
std::cout << std::endl << std::flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientFeature::prepare() {
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_askJwtSecret) {
|
||||||
|
// ask for a jwt secret
|
||||||
|
readJwtSecret();
|
||||||
|
} else if (_authentication && _haveServerPassword) {
|
||||||
|
// ask for a password
|
||||||
|
readPassword();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +242,8 @@ std::unique_ptr<GeneralClientConnection> ClientFeature::createConnection(
|
||||||
std::unique_ptr<Endpoint> endpoint(Endpoint::clientFactory(definition));
|
std::unique_ptr<Endpoint> endpoint(Endpoint::clientFactory(definition));
|
||||||
|
|
||||||
if (endpoint.get() == nullptr) {
|
if (endpoint.get() == nullptr) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "invalid value for --server.endpoint ('" << definition << "')";
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
|
<< "invalid value for --server.endpoint ('" << definition << "')";
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,24 +259,27 @@ std::unique_ptr<SimpleHttpClient> ClientFeature::createHttpClient() const {
|
||||||
return createHttpClient(_endpoint);
|
return createHttpClient(_endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SimpleHttpClient> ClientFeature::createHttpClient(std::string const& definition) const {
|
std::unique_ptr<SimpleHttpClient> ClientFeature::createHttpClient(
|
||||||
return createHttpClient(definition, SimpleHttpClientParams(_requestTimeout, _warn));
|
std::string const& definition) const {
|
||||||
|
return createHttpClient(definition,
|
||||||
|
SimpleHttpClientParams(_requestTimeout, _warn));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<httpclient::SimpleHttpClient> ClientFeature::createHttpClient(
|
std::unique_ptr<httpclient::SimpleHttpClient> ClientFeature::createHttpClient(
|
||||||
std::string const& definition,
|
std::string const& definition, SimpleHttpClientParams const& params) const {
|
||||||
SimpleHttpClientParams const& params) const {
|
|
||||||
std::unique_ptr<Endpoint> endpoint(Endpoint::clientFactory(definition));
|
std::unique_ptr<Endpoint> endpoint(Endpoint::clientFactory(definition));
|
||||||
|
|
||||||
if (endpoint.get() == nullptr) {
|
if (endpoint.get() == nullptr) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "invalid value for --server.endpoint ('" << definition << "')";
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
|
<< "invalid value for --server.endpoint ('" << definition << "')";
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GeneralClientConnection> connection(GeneralClientConnection::factory(endpoint, _requestTimeout,
|
std::unique_ptr<GeneralClientConnection> connection(
|
||||||
_connectionTimeout, _retries,
|
GeneralClientConnection::factory(endpoint, _requestTimeout,
|
||||||
_sslProtocol));
|
_connectionTimeout, _retries,
|
||||||
|
_sslProtocol));
|
||||||
|
|
||||||
return std::make_unique<SimpleHttpClient>(connection, params);
|
return std::make_unique<SimpleHttpClient>(connection, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,21 +290,23 @@ std::vector<std::string> ClientFeature::httpEndpoints() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return { http };
|
return {http};
|
||||||
}
|
}
|
||||||
|
|
||||||
int ClientFeature::runMain(int argc, char* argv[],
|
int ClientFeature::runMain(
|
||||||
std::function<int(int argc, char* argv[])> const& mainFunc) {
|
int argc, char* argv[],
|
||||||
|
std::function<int(int argc, char* argv[])> const& mainFunc) {
|
||||||
try {
|
try {
|
||||||
return mainFunc(argc, argv);
|
return mainFunc(argc, argv);
|
||||||
} catch (std::exception const& ex) {
|
} catch (std::exception const& ex) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
<< argv[0] << " terminated because of an unhandled exception: "
|
<< argv[0]
|
||||||
<< ex.what();
|
<< " terminated because of an unhandled exception: " << ex.what();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
<< argv[0] << " terminated because of an unhandled exception of unknown type";
|
<< argv[0]
|
||||||
|
<< " terminated because of an unhandled exception of unknown type";
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace httpclient {
|
||||||
class GeneralClientConnection;
|
class GeneralClientConnection;
|
||||||
class SimpleHttpClient;
|
class SimpleHttpClient;
|
||||||
struct SimpleHttpClientParams;
|
struct SimpleHttpClientParams;
|
||||||
}
|
} // namespace httpclient
|
||||||
|
|
||||||
class ClientFeature final : public application_features::ApplicationFeature,
|
class ClientFeature final : public application_features::ApplicationFeature,
|
||||||
public HttpEndpointProvider {
|
public HttpEndpointProvider {
|
||||||
|
@ -45,6 +45,7 @@ class ClientFeature final : public application_features::ApplicationFeature,
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ClientFeature(application_features::ApplicationServer* server,
|
ClientFeature(application_features::ApplicationServer* server,
|
||||||
|
bool allowJwtSecret,
|
||||||
double connectionTimeout = DEFAULT_CONNECTION_TIMEOUT,
|
double connectionTimeout = DEFAULT_CONNECTION_TIMEOUT,
|
||||||
double requestTimeout = DEFAULT_REQUEST_TIMEOUT);
|
double requestTimeout = DEFAULT_REQUEST_TIMEOUT);
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ class ClientFeature final : public application_features::ApplicationFeature,
|
||||||
void setUsername(std::string const& value) { _username = value; }
|
void setUsername(std::string const& value) { _username = value; }
|
||||||
std::string const& password() const { return _password; }
|
std::string const& password() const { return _password; }
|
||||||
void setPassword(std::string const& value) { _password = value; }
|
void setPassword(std::string const& value) { _password = value; }
|
||||||
|
std::string const& jwtSecret() const { return _jwtSecret; }
|
||||||
double connectionTimeout() const { return _connectionTimeout; }
|
double connectionTimeout() const { return _connectionTimeout; }
|
||||||
double requestTimeout() const { return _requestTimeout; }
|
double requestTimeout() const { return _requestTimeout; }
|
||||||
uint64_t maxPacketSize() const { return _maxPacketSize; }
|
uint64_t maxPacketSize() const { return _maxPacketSize; }
|
||||||
|
@ -75,7 +77,8 @@ class ClientFeature final : public application_features::ApplicationFeature,
|
||||||
std::unique_ptr<httpclient::SimpleHttpClient> createHttpClient(
|
std::unique_ptr<httpclient::SimpleHttpClient> createHttpClient(
|
||||||
std::string const& definition) const;
|
std::string const& definition) const;
|
||||||
std::unique_ptr<httpclient::SimpleHttpClient> createHttpClient(
|
std::unique_ptr<httpclient::SimpleHttpClient> createHttpClient(
|
||||||
std::string const& definition, httpclient::SimpleHttpClientParams const&) const;
|
std::string const& definition,
|
||||||
|
httpclient::SimpleHttpClientParams const&) const;
|
||||||
std::vector<std::string> httpEndpoints() override;
|
std::vector<std::string> httpEndpoints() override;
|
||||||
|
|
||||||
void setDatabaseName(std::string const& databaseName) {
|
void setDatabaseName(std::string const& databaseName) {
|
||||||
|
@ -92,26 +95,34 @@ class ClientFeature final : public application_features::ApplicationFeature,
|
||||||
|
|
||||||
bool getWarnConnect() { return _warnConnect; }
|
bool getWarnConnect() { return _warnConnect; }
|
||||||
|
|
||||||
static int runMain(int argc, char* argv[],
|
static int runMain(
|
||||||
std::function<int(int argc, char* argv[])> const& mainFunc);
|
int argc, char* argv[],
|
||||||
|
std::function<int(int argc, char* argv[])> const& mainFunc);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void readPassword();
|
||||||
|
void readJwtSecret();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _databaseName;
|
std::string _databaseName;
|
||||||
bool _authentication;
|
bool _authentication;
|
||||||
|
bool _askJwtSecret;
|
||||||
std::string _endpoint;
|
std::string _endpoint;
|
||||||
std::string _username;
|
std::string _username;
|
||||||
std::string _password;
|
std::string _password;
|
||||||
|
std::string _jwtSecret;
|
||||||
double _connectionTimeout;
|
double _connectionTimeout;
|
||||||
double _requestTimeout;
|
double _requestTimeout;
|
||||||
uint64_t _maxPacketSize;
|
uint64_t _maxPacketSize;
|
||||||
uint64_t _sslProtocol;
|
uint64_t _sslProtocol;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _allowJwtSecret;
|
||||||
size_t _retries;
|
size_t _retries;
|
||||||
bool _warn;
|
bool _warn;
|
||||||
bool _warnConnect;
|
bool _warnConnect;
|
||||||
bool _haveServerPassword;
|
bool _haveServerPassword;
|
||||||
};
|
};
|
||||||
}
|
} // namespace arangodb
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
|
|
||||||
#include "V8ClientConnection.h"
|
#include "V8ClientConnection.h"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <v8.h>
|
#include <v8.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "Basics/FileUtils.h"
|
#include "Basics/FileUtils.h"
|
||||||
#include "Basics/StringUtils.h"
|
#include "Basics/StringUtils.h"
|
||||||
|
@ -38,6 +38,7 @@
|
||||||
#include "SimpleHttpClient/GeneralClientConnection.h"
|
#include "SimpleHttpClient/GeneralClientConnection.h"
|
||||||
#include "SimpleHttpClient/SimpleHttpClient.h"
|
#include "SimpleHttpClient/SimpleHttpClient.h"
|
||||||
#include "SimpleHttpClient/SimpleHttpResult.h"
|
#include "SimpleHttpClient/SimpleHttpResult.h"
|
||||||
|
#include "Ssl/SslInterface.h"
|
||||||
#include "V8/v8-conv.h"
|
#include "V8/v8-conv.h"
|
||||||
#include "V8/v8-json.h"
|
#include "V8/v8-json.h"
|
||||||
#include "V8/v8-utils.h"
|
#include "V8/v8-utils.h"
|
||||||
|
@ -48,6 +49,35 @@ using namespace arangodb::basics;
|
||||||
using namespace arangodb::httpclient;
|
using namespace arangodb::httpclient;
|
||||||
using namespace arangodb::import;
|
using namespace arangodb::import;
|
||||||
|
|
||||||
|
std::string V8ClientConnection::JWT_SECRET = "";
|
||||||
|
|
||||||
|
std::string V8ClientConnection::jwtToken(std::string const& secret) {
|
||||||
|
VPackBuilder headerBuilder;
|
||||||
|
{
|
||||||
|
VPackObjectBuilder h(&headerBuilder);
|
||||||
|
headerBuilder.add("alg", VPackValue("HS256"));
|
||||||
|
headerBuilder.add("typ", VPackValue("JWT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
VPackBuilder bodyBuilder;
|
||||||
|
{
|
||||||
|
VPackObjectBuilder p(&bodyBuilder);
|
||||||
|
bodyBuilder.add("server_id", VPackValue("arangosh"));
|
||||||
|
bodyBuilder.add("iss", VPackValue("arangodb"));
|
||||||
|
bodyBuilder.add("iat", VPackValue(TRI_microtime() / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fullMessage(StringUtils::encodeBase64(headerBuilder.toJson()) +
|
||||||
|
"." +
|
||||||
|
StringUtils::encodeBase64(bodyBuilder.toJson()));
|
||||||
|
|
||||||
|
std::string signature = sslHMAC(
|
||||||
|
secret.c_str(), secret.length(), fullMessage.c_str(),
|
||||||
|
fullMessage.length(), rest::SslInterface::Algorithm::ALGORITHM_SHA256);
|
||||||
|
|
||||||
|
return fullMessage + "." + StringUtils::encodeBase64U(signature);
|
||||||
|
}
|
||||||
|
|
||||||
V8ClientConnection::V8ClientConnection(
|
V8ClientConnection::V8ClientConnection(
|
||||||
std::unique_ptr<GeneralClientConnection>& connection,
|
std::unique_ptr<GeneralClientConnection>& connection,
|
||||||
std::string const& database, std::string const& username,
|
std::string const& database, std::string const& username,
|
||||||
|
@ -65,8 +95,9 @@ V8ClientConnection::V8ClientConnection(
|
||||||
V8ClientConnection::~V8ClientConnection() {}
|
V8ClientConnection::~V8ClientConnection() {}
|
||||||
|
|
||||||
void V8ClientConnection::init(
|
void V8ClientConnection::init(
|
||||||
std::unique_ptr<GeneralClientConnection>& connection, std::string const& username,
|
std::unique_ptr<GeneralClientConnection>& connection,
|
||||||
std::string const& password, std::string const& databaseName) {
|
std::string const& username, std::string const& password,
|
||||||
|
std::string const& databaseName) {
|
||||||
_username = username;
|
_username = username;
|
||||||
_password = password;
|
_password = password;
|
||||||
_databaseName = databaseName;
|
_databaseName = databaseName;
|
||||||
|
@ -74,13 +105,18 @@ void V8ClientConnection::init(
|
||||||
SimpleHttpClientParams params(_requestTimeout, false);
|
SimpleHttpClientParams params(_requestTimeout, false);
|
||||||
params.setLocationRewriter(this, &rewriteLocation);
|
params.setLocationRewriter(this, &rewriteLocation);
|
||||||
params.setUserNamePassword("/", _username, _password);
|
params.setUserNamePassword("/", _username, _password);
|
||||||
|
|
||||||
|
if (!JWT_SECRET.empty()) {
|
||||||
|
params.setJwt(jwtToken(JWT_SECRET));
|
||||||
|
}
|
||||||
|
|
||||||
_client.reset(new SimpleHttpClient(connection, params));
|
_client.reset(new SimpleHttpClient(connection, params));
|
||||||
|
|
||||||
// connect to server and get version number
|
// connect to server and get version number
|
||||||
std::unordered_map<std::string, std::string> headerFields;
|
std::unordered_map<std::string, std::string> headerFields;
|
||||||
std::unique_ptr<SimpleHttpResult> result(
|
std::unique_ptr<SimpleHttpResult> result(
|
||||||
_client->request(rest::RequestType::GET,
|
_client->request(rest::RequestType::GET, "/_api/version?details=true",
|
||||||
"/_api/version?details=true", nullptr, 0, headerFields));
|
nullptr, 0, headerFields));
|
||||||
|
|
||||||
if (result.get() == nullptr || !result->isComplete()) {
|
if (result.get() == nullptr || !result->isComplete()) {
|
||||||
// save error message
|
// save error message
|
||||||
|
@ -89,7 +125,8 @@ void V8ClientConnection::init(
|
||||||
} else {
|
} else {
|
||||||
_lastHttpReturnCode = result->getHttpReturnCode();
|
_lastHttpReturnCode = result->getHttpReturnCode();
|
||||||
|
|
||||||
if (result->getHttpReturnCode() == static_cast<int>(rest::ResponseCode::OK)) {
|
if (result->getHttpReturnCode() ==
|
||||||
|
static_cast<int>(rest::ResponseCode::OK)) {
|
||||||
try {
|
try {
|
||||||
std::shared_ptr<VPackBuilder> parsedBody = result->getBodyVelocyPack();
|
std::shared_ptr<VPackBuilder> parsedBody = result->getBodyVelocyPack();
|
||||||
VPackSlice const body = parsedBody->slice();
|
VPackSlice const body = parsedBody->slice();
|
||||||
|
@ -109,11 +146,13 @@ void V8ClientConnection::init(
|
||||||
}
|
}
|
||||||
std::string const versionString =
|
std::string const versionString =
|
||||||
VelocyPackHelper::getStringValue(body, "version", "");
|
VelocyPackHelper::getStringValue(body, "version", "");
|
||||||
std::pair<int, int> version = rest::Version::parseVersionString(versionString);
|
std::pair<int, int> version =
|
||||||
|
rest::Version::parseVersionString(versionString);
|
||||||
if (version.first < 3) {
|
if (version.first < 3) {
|
||||||
// major version of server is too low
|
// major version of server is too low
|
||||||
_client->disconnect();
|
_client->disconnect();
|
||||||
_lastErrorMessage = "Server version number ('" + versionString + "') is too low. Expecting 3.0 or higher";
|
_lastErrorMessage = "Server version number ('" + versionString +
|
||||||
|
"') is too low. Expecting 3.0 or higher";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +211,8 @@ void V8ClientConnection::reconnect(ClientFeature* client) {
|
||||||
try {
|
try {
|
||||||
std::unique_ptr<GeneralClientConnection> connection =
|
std::unique_ptr<GeneralClientConnection> connection =
|
||||||
client->createConnection(client->endpoint());
|
client->createConnection(client->endpoint());
|
||||||
init(connection, client->username(), client->password(), client->databaseName());
|
init(connection, client->username(), client->password(),
|
||||||
|
client->databaseName());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::string errorMessage = "error in '" + client->endpoint() + "'";
|
std::string errorMessage = "error in '" + client->endpoint() + "'";
|
||||||
throw errorMessage;
|
throw errorMessage;
|
||||||
|
@ -180,16 +220,17 @@ void V8ClientConnection::reconnect(ClientFeature* client) {
|
||||||
|
|
||||||
if (isConnected() &&
|
if (isConnected() &&
|
||||||
_lastHttpReturnCode == static_cast<int>(rest::ResponseCode::OK)) {
|
_lastHttpReturnCode == static_cast<int>(rest::ResponseCode::OK)) {
|
||||||
LOG_TOPIC(INFO, arangodb::Logger::FIXME) << "Connected to ArangoDB "
|
LOG_TOPIC(INFO, arangodb::Logger::FIXME)
|
||||||
<< "'" << endpointSpecification() << "', "
|
<< "Connected to ArangoDB "
|
||||||
<< "version " << _version << " [" << _mode << "], "
|
<< "'" << endpointSpecification() << "', "
|
||||||
<< "database '" << _databaseName << "', "
|
<< "version " << _version << " [" << _mode << "], "
|
||||||
<< "username: '" << _username << "'";
|
<< "database '" << _databaseName << "', "
|
||||||
|
<< "username: '" << _username << "'";
|
||||||
} else {
|
} else {
|
||||||
if (client->getWarnConnect()) {
|
if (client->getWarnConnect()) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
<< "Could not connect to endpoint '" << client->endpoint()
|
<< "Could not connect to endpoint '" << client->endpoint()
|
||||||
<< "', username: '" << client->username() << "'";
|
<< "', username: '" << client->username() << "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string errorMsg = "could not connect";
|
std::string errorMsg = "could not connect";
|
||||||
|
@ -274,8 +315,7 @@ static V8ClientConnection* CreateV8ClientConnection(
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void ClientConnection_DestructorCallback(
|
static void ClientConnection_DestructorCallback(
|
||||||
const v8::WeakCallbackInfo<v8::Persistent<v8::External>>&
|
const v8::WeakCallbackInfo<v8::Persistent<v8::External>>& data) {
|
||||||
data) {
|
|
||||||
auto persistent = data.GetParameter();
|
auto persistent = data.GetParameter();
|
||||||
auto myConnection =
|
auto myConnection =
|
||||||
v8::Local<v8::External>::New(data.GetIsolate(), *persistent);
|
v8::Local<v8::External>::New(data.GetIsolate(), *persistent);
|
||||||
|
@ -335,14 +375,14 @@ static void ClientConnection_ConstructorCallback(
|
||||||
CreateV8ClientConnection(connection, client));
|
CreateV8ClientConnection(connection, client));
|
||||||
|
|
||||||
if (v8connection->isConnected() &&
|
if (v8connection->isConnected() &&
|
||||||
v8connection->lastHttpReturnCode() ==
|
v8connection->lastHttpReturnCode() == (int)rest::ResponseCode::OK) {
|
||||||
(int)rest::ResponseCode::OK) {
|
LOG_TOPIC(INFO, arangodb::Logger::FIXME)
|
||||||
LOG_TOPIC(INFO, arangodb::Logger::FIXME) << "Connected to ArangoDB "
|
<< "Connected to ArangoDB "
|
||||||
<< "'" << v8connection->endpointSpecification() << "', "
|
<< "'" << v8connection->endpointSpecification() << "', "
|
||||||
<< "version " << v8connection->version() << " ["
|
<< "version " << v8connection->version() << " [" << v8connection->mode()
|
||||||
<< v8connection->mode() << "], "
|
<< "], "
|
||||||
<< "database '" << v8connection->databaseName() << "', "
|
<< "database '" << v8connection->databaseName() << "', "
|
||||||
<< "username: '" << v8connection->username() << "'";
|
<< "username: '" << v8connection->username() << "'";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
std::string errorMessage =
|
std::string errorMessage =
|
||||||
|
@ -394,7 +434,7 @@ static void ClientConnection_reconnect(
|
||||||
std::string password;
|
std::string password;
|
||||||
|
|
||||||
if (args.Length() < 4) {
|
if (args.Length() < 4) {
|
||||||
ConsoleFeature* console =
|
ConsoleFeature* console =
|
||||||
ApplicationServer::getFeature<ConsoleFeature>("Console");
|
ApplicationServer::getFeature<ConsoleFeature>("Console");
|
||||||
|
|
||||||
if (console->isEnabled()) {
|
if (console->isEnabled()) {
|
||||||
|
@ -428,9 +468,10 @@ static void ClientConnection_reconnect(
|
||||||
TRI_V8_THROW_EXCEPTION_PARAMETER(errorMessage.c_str());
|
TRI_V8_THROW_EXCEPTION_PARAMETER(errorMessage.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TRI_ExecuteJavaScriptString(isolate, isolate->GetCurrentContext(),
|
TRI_ExecuteJavaScriptString(
|
||||||
TRI_V8_STRING(isolate, "require('internal').db._flushCache();"),
|
isolate, isolate->GetCurrentContext(),
|
||||||
TRI_V8_ASCII_STRING(isolate, "reload db object"), false);
|
TRI_V8_STRING(isolate, "require('internal').db._flushCache();"),
|
||||||
|
TRI_V8_ASCII_STRING(isolate, "reload db object"), false);
|
||||||
|
|
||||||
TRI_V8_RETURN_TRUE();
|
TRI_V8_RETURN_TRUE();
|
||||||
TRI_V8_TRY_CATCH_END
|
TRI_V8_TRY_CATCH_END
|
||||||
|
@ -956,7 +997,8 @@ static void ClientConnection_importCsv(
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the options
|
// extract the options
|
||||||
v8::Handle<v8::String> separatorKey = TRI_V8_ASCII_STRING(isolate, "separator");
|
v8::Handle<v8::String> separatorKey =
|
||||||
|
TRI_V8_ASCII_STRING(isolate, "separator");
|
||||||
v8::Handle<v8::String> quoteKey = TRI_V8_ASCII_STRING(isolate, "quote");
|
v8::Handle<v8::String> quoteKey = TRI_V8_ASCII_STRING(isolate, "quote");
|
||||||
|
|
||||||
std::string separator = ",";
|
std::string separator = ",";
|
||||||
|
@ -1025,7 +1067,7 @@ static void ClientConnection_importCsv(
|
||||||
for (std::string const& msg : ih.getErrorMessages()) {
|
for (std::string const& msg : ih.getErrorMessages()) {
|
||||||
error.append(msg + ";\t");
|
error.append(msg + ";\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED, error.c_str());
|
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED, error.c_str());
|
||||||
TRI_V8_TRY_CATCH_END
|
TRI_V8_TRY_CATCH_END
|
||||||
}
|
}
|
||||||
|
@ -1089,7 +1131,7 @@ static void ClientConnection_importJson(
|
||||||
|
|
||||||
TRI_V8_RETURN(result);
|
TRI_V8_RETURN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string error = "error messages:";
|
std::string error = "error messages:";
|
||||||
for (std::string const& msg : ih.getErrorMessages()) {
|
for (std::string const& msg : ih.getErrorMessages()) {
|
||||||
error.append(msg + ";\t");
|
error.append(msg + ";\t");
|
||||||
|
@ -1174,7 +1216,7 @@ static void ClientConnection_isConnected(
|
||||||
|
|
||||||
if (v8connection->isConnected()) {
|
if (v8connection->isConnected()) {
|
||||||
TRI_V8_RETURN_TRUE();
|
TRI_V8_RETURN_TRUE();
|
||||||
}
|
}
|
||||||
TRI_V8_RETURN_FALSE();
|
TRI_V8_RETURN_FALSE();
|
||||||
TRI_V8_TRY_CATCH_END
|
TRI_V8_TRY_CATCH_END
|
||||||
}
|
}
|
||||||
|
@ -1411,7 +1453,7 @@ v8::Handle<v8::Value> V8ClientConnection::requestDataRaw(
|
||||||
_httpResult->setHttpReturnCode(500);
|
_httpResult->setHttpReturnCode(500);
|
||||||
_httpResult->setResultType(SimpleHttpResult::COULD_NOT_CONNECT);
|
_httpResult->setResultType(SimpleHttpResult::COULD_NOT_CONNECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Handle<v8::Object> result = v8::Object::New(isolate);
|
v8::Handle<v8::Object> result = v8::Object::New(isolate);
|
||||||
|
|
||||||
TRI_ASSERT(_httpResult != nullptr);
|
TRI_ASSERT(_httpResult != nullptr);
|
||||||
|
@ -1452,7 +1494,7 @@ v8::Handle<v8::Value> V8ClientConnection::requestDataRaw(
|
||||||
}
|
}
|
||||||
|
|
||||||
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::Error),
|
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::Error),
|
||||||
v8::Boolean::New(isolate, true));
|
v8::Boolean::New(isolate, true));
|
||||||
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorNum),
|
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorNum),
|
||||||
v8::Integer::New(isolate, errorNumber));
|
v8::Integer::New(isolate, errorNumber));
|
||||||
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorMessage),
|
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorMessage),
|
||||||
|
@ -1473,14 +1515,14 @@ v8::Handle<v8::Value> V8ClientConnection::requestDataRaw(
|
||||||
std::string returnMessage(_httpResult->getHttpReturnMessage());
|
std::string returnMessage(_httpResult->getHttpReturnMessage());
|
||||||
|
|
||||||
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::Error),
|
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::Error),
|
||||||
v8::Boolean::New(isolate, true));
|
v8::Boolean::New(isolate, true));
|
||||||
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorNum),
|
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorNum),
|
||||||
v8::Integer::New(isolate, _lastHttpReturnCode));
|
v8::Integer::New(isolate, _lastHttpReturnCode));
|
||||||
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorMessage),
|
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::ErrorMessage),
|
||||||
TRI_V8_STD_STRING(isolate, returnMessage));
|
TRI_V8_STD_STRING(isolate, returnMessage));
|
||||||
} else {
|
} else {
|
||||||
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::Error),
|
result->ForceSet(TRI_V8_STD_STRING(isolate, StaticStrings::Error),
|
||||||
v8::Boolean::New(isolate, false));
|
v8::Boolean::New(isolate, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// got a body, copy it into the result
|
// got a body, copy it into the result
|
||||||
|
@ -1609,7 +1651,8 @@ void V8ClientConnection::initServer(v8::Isolate* isolate,
|
||||||
v8::Local<v8::FunctionTemplate> connection_templ =
|
v8::Local<v8::FunctionTemplate> connection_templ =
|
||||||
v8::FunctionTemplate::New(isolate);
|
v8::FunctionTemplate::New(isolate);
|
||||||
|
|
||||||
connection_templ->SetClassName(TRI_V8_ASCII_STRING(isolate, "ArangoConnection"));
|
connection_templ->SetClassName(
|
||||||
|
TRI_V8_ASCII_STRING(isolate, "ArangoConnection"));
|
||||||
|
|
||||||
v8::Local<v8::ObjectTemplate> connection_proto =
|
v8::Local<v8::ObjectTemplate> connection_proto =
|
||||||
connection_templ->PrototypeTemplate();
|
connection_templ->PrototypeTemplate();
|
||||||
|
@ -1622,8 +1665,9 @@ void V8ClientConnection::initServer(v8::Isolate* isolate,
|
||||||
isolate, "DELETE_RAW",
|
isolate, "DELETE_RAW",
|
||||||
v8::FunctionTemplate::New(isolate, ClientConnection_httpDeleteRaw));
|
v8::FunctionTemplate::New(isolate, ClientConnection_httpDeleteRaw));
|
||||||
|
|
||||||
connection_proto->Set(isolate, "GET", v8::FunctionTemplate::New(
|
connection_proto->Set(
|
||||||
isolate, ClientConnection_httpGet));
|
isolate, "GET",
|
||||||
|
v8::FunctionTemplate::New(isolate, ClientConnection_httpGet));
|
||||||
|
|
||||||
connection_proto->Set(
|
connection_proto->Set(
|
||||||
isolate, "GET_RAW",
|
isolate, "GET_RAW",
|
||||||
|
@ -1661,8 +1705,9 @@ void V8ClientConnection::initServer(v8::Isolate* isolate,
|
||||||
isolate, "POST_RAW",
|
isolate, "POST_RAW",
|
||||||
v8::FunctionTemplate::New(isolate, ClientConnection_httpPostRaw));
|
v8::FunctionTemplate::New(isolate, ClientConnection_httpPostRaw));
|
||||||
|
|
||||||
connection_proto->Set(isolate, "PUT", v8::FunctionTemplate::New(
|
connection_proto->Set(
|
||||||
isolate, ClientConnection_httpPut));
|
isolate, "PUT",
|
||||||
|
v8::FunctionTemplate::New(isolate, ClientConnection_httpPut));
|
||||||
connection_proto->Set(
|
connection_proto->Set(
|
||||||
isolate, "PUT_RAW",
|
isolate, "PUT_RAW",
|
||||||
v8::FunctionTemplate::New(isolate, ClientConnection_httpPutRaw));
|
v8::FunctionTemplate::New(isolate, ClientConnection_httpPutRaw));
|
||||||
|
@ -1690,10 +1735,10 @@ void V8ClientConnection::initServer(v8::Isolate* isolate,
|
||||||
connection_proto->Set(
|
connection_proto->Set(
|
||||||
isolate, "reconnect",
|
isolate, "reconnect",
|
||||||
v8::FunctionTemplate::New(isolate, ClientConnection_reconnect, v8client));
|
v8::FunctionTemplate::New(isolate, ClientConnection_reconnect, v8client));
|
||||||
|
|
||||||
connection_proto->Set(
|
connection_proto->Set(isolate, "connectedUser",
|
||||||
isolate, "connectedUser",
|
v8::FunctionTemplate::New(
|
||||||
v8::FunctionTemplate::New(isolate, ClientConnection_connectedUser, v8client));
|
isolate, ClientConnection_connectedUser, v8client));
|
||||||
|
|
||||||
connection_proto->Set(
|
connection_proto->Set(
|
||||||
isolate, "toString",
|
isolate, "toString",
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace httpclient {
|
||||||
class GeneralClientConnection;
|
class GeneralClientConnection;
|
||||||
class SimpleHttpClient;
|
class SimpleHttpClient;
|
||||||
class SimpleHttpResult;
|
class SimpleHttpResult;
|
||||||
}
|
} // namespace httpclient
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief class for http requests
|
/// @brief class for http requests
|
||||||
|
@ -48,6 +48,13 @@ class V8ClientConnection {
|
||||||
V8ClientConnection(V8ClientConnection const&) = delete;
|
V8ClientConnection(V8ClientConnection const&) = delete;
|
||||||
V8ClientConnection& operator=(V8ClientConnection const&) = delete;
|
V8ClientConnection& operator=(V8ClientConnection const&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void setJwtSecret(std::string const& jwtSecret) { JWT_SECRET = jwtSecret; }
|
||||||
|
static std::string jwtToken(std::string const& secret);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string JWT_SECRET;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
V8ClientConnection(
|
V8ClientConnection(
|
||||||
std::unique_ptr<httpclient::GeneralClientConnection>& connection,
|
std::unique_ptr<httpclient::GeneralClientConnection>& connection,
|
||||||
|
@ -104,7 +111,8 @@ class V8ClientConnection {
|
||||||
static std::string rewriteLocation(void*, std::string const&);
|
static std::string rewriteLocation(void*, std::string const&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init(std::unique_ptr<httpclient::GeneralClientConnection>&, std::string const&, std::string const&, std::string const&);
|
void init(std::unique_ptr<httpclient::GeneralClientConnection>&,
|
||||||
|
std::string const&, std::string const&, std::string const&);
|
||||||
|
|
||||||
v8::Handle<v8::Value> requestData(
|
v8::Handle<v8::Value> requestData(
|
||||||
v8::Isolate* isolate, rest::RequestType method,
|
v8::Isolate* isolate, rest::RequestType method,
|
||||||
|
@ -132,6 +140,6 @@ class V8ClientConnection {
|
||||||
std::string _version;
|
std::string _version;
|
||||||
std::string _mode;
|
std::string _mode;
|
||||||
};
|
};
|
||||||
}
|
} // namespace arangodb
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
#include "Basics/ArangoGlobalContext.h"
|
#include "Basics/ArangoGlobalContext.h"
|
||||||
#include "Basics/FileUtils.h"
|
#include "Basics/FileUtils.h"
|
||||||
#include "Basics/StringUtils.h"
|
#include "Basics/StringUtils.h"
|
||||||
#include "Basics/terminal-utils.h"
|
|
||||||
#include "Basics/Utf8Helper.h"
|
#include "Basics/Utf8Helper.h"
|
||||||
|
#include "Basics/terminal-utils.h"
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
#include "ProgramOptions/ProgramOptions.h"
|
#include "ProgramOptions/ProgramOptions.h"
|
||||||
#include "ProgramOptions/Section.h"
|
#include "ProgramOptions/Section.h"
|
||||||
|
@ -101,13 +101,13 @@ void V8ShellFeature::validateOptions(
|
||||||
FATAL_ERROR_EXIT();
|
FATAL_ERROR_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_TOPIC(DEBUG, Logger::V8) << "using Javascript startup files at '"
|
LOG_TOPIC(DEBUG, Logger::V8)
|
||||||
<< _startupDirectory << "'";
|
<< "using Javascript startup files at '" << _startupDirectory << "'";
|
||||||
|
|
||||||
if (!_moduleDirectory.empty()) {
|
if (!_moduleDirectory.empty()) {
|
||||||
LOG_TOPIC(DEBUG, Logger::V8) << "using Javascript modules at '"
|
LOG_TOPIC(DEBUG, Logger::V8)
|
||||||
<< StringUtils::join(_moduleDirectory, ";")
|
<< "using Javascript modules at '"
|
||||||
<< "'";
|
<< StringUtils::join(_moduleDirectory, ";") << "'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,6 +281,12 @@ V8ClientConnection* V8ShellFeature::setup(
|
||||||
client = dynamic_cast<ClientFeature*>(server()->feature("Client"));
|
client = dynamic_cast<ClientFeature*>(server()->feature("Client"));
|
||||||
|
|
||||||
if (client != nullptr && client->isEnabled()) {
|
if (client != nullptr && client->isEnabled()) {
|
||||||
|
auto jwtSecret = client->jwtSecret();
|
||||||
|
|
||||||
|
if (!jwtSecret.empty()) {
|
||||||
|
V8ClientConnection::setJwtSecret(jwtSecret);
|
||||||
|
}
|
||||||
|
|
||||||
auto connection = client->createConnection();
|
auto connection = client->createConnection();
|
||||||
v8connection = std::make_unique<V8ClientConnection>(
|
v8connection = std::make_unique<V8ClientConnection>(
|
||||||
connection, client->databaseName(), client->username(),
|
connection, client->databaseName(), client->username(),
|
||||||
|
@ -354,7 +360,8 @@ int V8ShellFeature::runShell(std::vector<std::string> const& positionals) {
|
||||||
std::string input =
|
std::string input =
|
||||||
v8LineEditor.prompt(prompt._colored, prompt._plain, eof);
|
v8LineEditor.prompt(prompt._colored, prompt._plain, eof);
|
||||||
|
|
||||||
if (eof == ShellBase::EOF_FORCE_ABORT || (eof == ShellBase::EOF_ABORT && lastEmpty)) {
|
if (eof == ShellBase::EOF_FORCE_ABORT ||
|
||||||
|
(eof == ShellBase::EOF_ABORT && lastEmpty)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,7 +451,7 @@ int V8ShellFeature::runShell(std::vector<std::string> const& positionals) {
|
||||||
V8PlatformFeature::resetOutOfMemory(_isolate);
|
V8PlatformFeature::resetOutOfMemory(_isolate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_console->quiet()) {
|
if (!_console->quiet()) {
|
||||||
_console->printLine("");
|
_console->printLine("");
|
||||||
_console->printByeBye();
|
_console->printByeBye();
|
||||||
|
@ -473,7 +480,8 @@ bool V8ShellFeature::runScript(std::vector<std::string> const& files,
|
||||||
|
|
||||||
for (auto const& file : files) {
|
for (auto const& file : files) {
|
||||||
if (!FileUtils::exists(file)) {
|
if (!FileUtils::exists(file)) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error: Javascript file not found: '" << file << "'";
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
|
<< "error: Javascript file not found: '" << file << "'";
|
||||||
ok = false;
|
ok = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -598,7 +606,8 @@ bool V8ShellFeature::jslint(std::vector<std::string> const& files) {
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
for (auto& file : files) {
|
for (auto& file : files) {
|
||||||
if (!FileUtils::exists(file)) {
|
if (!FileUtils::exists(file)) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error: Javascript file not found: '" << file << "'";
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
|
<< "error: Javascript file not found: '" << file << "'";
|
||||||
ok = false;
|
ok = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -610,9 +619,8 @@ bool V8ShellFeature::jslint(std::vector<std::string> const& files) {
|
||||||
context->Global()->Set(TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS"),
|
context->Global()->Set(TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS"),
|
||||||
sysTestFiles);
|
sysTestFiles);
|
||||||
|
|
||||||
context->Global()->Set(
|
context->Global()->Set(TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS_RESULT"),
|
||||||
TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS_RESULT"),
|
v8::True(_isolate));
|
||||||
v8::True(_isolate));
|
|
||||||
|
|
||||||
// run tests
|
// run tests
|
||||||
auto input = TRI_V8_ASCII_STRING(
|
auto input = TRI_V8_ASCII_STRING(
|
||||||
|
@ -624,7 +632,8 @@ bool V8ShellFeature::jslint(std::vector<std::string> const& files) {
|
||||||
TRI_ExecuteJavaScriptString(_isolate, context, input, name, true);
|
TRI_ExecuteJavaScriptString(_isolate, context, input, name, true);
|
||||||
|
|
||||||
if (tryCatch.HasCaught()) {
|
if (tryCatch.HasCaught()) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << TRI_StringifyV8Exception(_isolate, &tryCatch);
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
|
<< TRI_StringifyV8Exception(_isolate, &tryCatch);
|
||||||
ok = false;
|
ok = false;
|
||||||
} else {
|
} else {
|
||||||
bool res = TRI_ObjectToBoolean(context->Global()->Get(
|
bool res = TRI_ObjectToBoolean(context->Global()->Get(
|
||||||
|
@ -660,7 +669,8 @@ bool V8ShellFeature::runUnitTests(std::vector<std::string> const& files,
|
||||||
|
|
||||||
for (auto const& file : files) {
|
for (auto const& file : files) {
|
||||||
if (!FileUtils::exists(file)) {
|
if (!FileUtils::exists(file)) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error: Javascript file not found: '" << file << "'";
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
|
<< "error: Javascript file not found: '" << file << "'";
|
||||||
ok = false;
|
ok = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -669,15 +679,13 @@ bool V8ShellFeature::runUnitTests(std::vector<std::string> const& files,
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRI_AddGlobalVariableVocbase(_isolate,
|
TRI_AddGlobalVariableVocbase(
|
||||||
TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS"),
|
_isolate, TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS"), sysTestFiles);
|
||||||
sysTestFiles);
|
|
||||||
|
|
||||||
// do not use TRI_AddGlobalVariableVocBase because it creates read-only
|
// do not use TRI_AddGlobalVariableVocBase because it creates read-only
|
||||||
// variables!!
|
// variables!!
|
||||||
context->Global()->Set(
|
context->Global()->Set(TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS_RESULT"),
|
||||||
TRI_V8_ASCII_STRING(_isolate, "SYS_UNIT_TESTS_RESULT"),
|
v8::True(_isolate));
|
||||||
v8::True(_isolate));
|
|
||||||
|
|
||||||
// run tests
|
// run tests
|
||||||
auto input = TRI_V8_ASCII_STRING(
|
auto input = TRI_V8_ASCII_STRING(
|
||||||
|
@ -866,19 +874,19 @@ void V8ShellFeature::initGlobals() {
|
||||||
v8::FunctionTemplate::New(_isolate, JS_CompareString)->GetFunction());
|
v8::FunctionTemplate::New(_isolate, JS_CompareString)->GetFunction());
|
||||||
|
|
||||||
TRI_AddGlobalVariableVocbase(
|
TRI_AddGlobalVariableVocbase(
|
||||||
_isolate,
|
_isolate, TRI_V8_ASCII_STRING(_isolate, "ARANGODB_CLIENT_VERSION"),
|
||||||
TRI_V8_ASCII_STRING(_isolate, "ARANGODB_CLIENT_VERSION"),
|
|
||||||
v8::FunctionTemplate::New(_isolate, JS_VersionClient)->GetFunction());
|
v8::FunctionTemplate::New(_isolate, JS_VersionClient)->GetFunction());
|
||||||
|
|
||||||
// is quite
|
// is quite
|
||||||
TRI_AddGlobalVariableVocbase(_isolate,
|
TRI_AddGlobalVariableVocbase(_isolate,
|
||||||
TRI_V8_ASCII_STRING(_isolate, "ARANGO_QUIET"),
|
TRI_V8_ASCII_STRING(_isolate, "ARANGO_QUIET"),
|
||||||
v8::Boolean::New(_isolate, _console->quiet()));
|
v8::Boolean::New(_isolate, _console->quiet()));
|
||||||
|
|
||||||
auto ctx = ArangoGlobalContext::CONTEXT;
|
auto ctx = ArangoGlobalContext::CONTEXT;
|
||||||
|
|
||||||
if (ctx == nullptr) {
|
if (ctx == nullptr) {
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "failed to get global context. ";
|
LOG_TOPIC(ERR, arangodb::Logger::FIXME)
|
||||||
|
<< "failed to get global context. ";
|
||||||
FATAL_ERROR_EXIT();
|
FATAL_ERROR_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1002,15 +1010,17 @@ void V8ShellFeature::loadModules(ShellFeature::RunMode runMode) {
|
||||||
for (size_t i = 0; i < files.size(); ++i) {
|
for (size_t i = 0; i < files.size(); ++i) {
|
||||||
switch (loader.loadScript(_isolate, context, files[i], nullptr)) {
|
switch (loader.loadScript(_isolate, context, files[i], nullptr)) {
|
||||||
case JSLoader::eSuccess:
|
case JSLoader::eSuccess:
|
||||||
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "loaded JavaScript file '" << files[i] << "'";
|
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
|
||||||
|
<< "loaded JavaScript file '" << files[i] << "'";
|
||||||
break;
|
break;
|
||||||
case JSLoader::eFailLoad:
|
case JSLoader::eFailLoad:
|
||||||
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "cannot load JavaScript file '" << files[i] << "'";
|
LOG_TOPIC(FATAL, arangodb::Logger::FIXME)
|
||||||
|
<< "cannot load JavaScript file '" << files[i] << "'";
|
||||||
FATAL_ERROR_EXIT();
|
FATAL_ERROR_EXIT();
|
||||||
break;
|
break;
|
||||||
case JSLoader::eFailExecute:
|
case JSLoader::eFailExecute:
|
||||||
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "error during execution of JavaScript file '" << files[i]
|
LOG_TOPIC(FATAL, arangodb::Logger::FIXME)
|
||||||
<< "'";
|
<< "error during execution of JavaScript file '" << files[i] << "'";
|
||||||
FATAL_ERROR_EXIT();
|
FATAL_ERROR_EXIT();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ int main(int argc, char* argv[]) {
|
||||||
int ret = EXIT_SUCCESS;
|
int ret = EXIT_SUCCESS;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
server.addFeature(new ClientFeature(&server));
|
server.addFeature(new ClientFeature(&server, true));
|
||||||
server.addFeature(new ConfigFeature(&server, name));
|
server.addFeature(new ConfigFeature(&server, name));
|
||||||
server.addFeature(new ConsoleFeature(&server));
|
server.addFeature(new ConsoleFeature(&server));
|
||||||
server.addFeature(new LanguageFeature(&server));
|
server.addFeature(new LanguageFeature(&server));
|
||||||
|
|
|
@ -96,7 +96,7 @@ SimpleHttpClient::~SimpleHttpClient() {
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// public methods
|
// public methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
void SimpleHttpClient::setAborted(bool value) noexcept {
|
void SimpleHttpClient::setAborted(bool value) noexcept {
|
||||||
_aborted.store(value, std::memory_order_release);
|
_aborted.store(value, std::memory_order_release);
|
||||||
setInterrupted(value);
|
setInterrupted(value);
|
||||||
|
@ -160,7 +160,7 @@ SimpleHttpResult* SimpleHttpClient::retryRequest(
|
||||||
std::unordered_map<std::string, std::string> const& headers) {
|
std::unordered_map<std::string, std::string> const& headers) {
|
||||||
SimpleHttpResult* result = nullptr;
|
SimpleHttpResult* result = nullptr;
|
||||||
size_t tries = 0;
|
size_t tries = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
TRI_ASSERT(result == nullptr);
|
TRI_ASSERT(result == nullptr);
|
||||||
|
|
||||||
|
@ -174,18 +174,19 @@ SimpleHttpResult* SimpleHttpClient::retryRequest(
|
||||||
result = nullptr;
|
result = nullptr;
|
||||||
|
|
||||||
if (tries++ >= _params._maxRetries) {
|
if (tries++ >= _params._maxRetries) {
|
||||||
LOG_TOPIC(WARN, arangodb::Logger::HTTPCLIENT) << "" << _params._retryMessage
|
LOG_TOPIC(WARN, arangodb::Logger::HTTPCLIENT)
|
||||||
<< " - no retries left";
|
<< "" << _params._retryMessage << " - no retries left";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAborted()) {
|
if (isAborted()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_params._retryMessage.empty() && (_params._maxRetries - tries) > 0) {
|
if (!_params._retryMessage.empty() && (_params._maxRetries - tries) > 0) {
|
||||||
LOG_TOPIC(WARN, arangodb::Logger::HTTPCLIENT) << "" << _params._retryMessage
|
LOG_TOPIC(WARN, arangodb::Logger::HTTPCLIENT)
|
||||||
<< " - retries left: " << (_params._maxRetries - tries);
|
<< "" << _params._retryMessage
|
||||||
|
<< " - retries left: " << (_params._maxRetries - tries);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1 microsecond == 10^-6 seconds
|
// 1 microsecond == 10^-6 seconds
|
||||||
|
@ -352,7 +353,8 @@ SimpleHttpResult* SimpleHttpClient::doRequest(
|
||||||
// progress is made (but without an error), this then means
|
// progress is made (but without an error), this then means
|
||||||
// that the server has closed the connection and we must
|
// that the server has closed the connection and we must
|
||||||
// process the body one more time:
|
// process the body one more time:
|
||||||
_result->setContentLength(_readBuffer.length() - _readBufferOffset);
|
_result->setContentLength(_readBuffer.length() -
|
||||||
|
_readBufferOffset);
|
||||||
}
|
}
|
||||||
processBody();
|
processBody();
|
||||||
}
|
}
|
||||||
|
@ -530,9 +532,11 @@ void SimpleHttpClient::setRequest(
|
||||||
|
|
||||||
// append hostname
|
// append hostname
|
||||||
std::string hostname = _connection->getEndpoint()->host();
|
std::string hostname = _connection->getEndpoint()->host();
|
||||||
|
|
||||||
LOG_TOPIC(DEBUG, Logger::HTTPCLIENT) << "request to " << hostname << ": " << GeneralRequest::translateMethod(method) << ' ' << *l;
|
LOG_TOPIC(DEBUG, Logger::HTTPCLIENT)
|
||||||
|
<< "request to " << hostname << ": "
|
||||||
|
<< GeneralRequest::translateMethod(method) << ' ' << *l;
|
||||||
|
|
||||||
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("Host: "));
|
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("Host: "));
|
||||||
_writeBuffer.appendText(hostname);
|
_writeBuffer.appendText(hostname);
|
||||||
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("\r\n"));
|
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("\r\n"));
|
||||||
|
@ -554,15 +558,14 @@ void SimpleHttpClient::setRequest(
|
||||||
}
|
}
|
||||||
|
|
||||||
// do basic authorization
|
// do basic authorization
|
||||||
if (!_params._basicAuth.empty()) {
|
|
||||||
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("Authorization: Basic "));
|
|
||||||
_writeBuffer.appendText(_params._basicAuth);
|
|
||||||
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("\r\n"));
|
|
||||||
}
|
|
||||||
if (!_params._jwt.empty()) {
|
if (!_params._jwt.empty()) {
|
||||||
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("Authorization: bearer "));
|
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("Authorization: bearer "));
|
||||||
_writeBuffer.appendText(_params._jwt);
|
_writeBuffer.appendText(_params._jwt);
|
||||||
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("\r\n"));
|
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("\r\n"));
|
||||||
|
} else if (!_params._basicAuth.empty()) {
|
||||||
|
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("Authorization: Basic "));
|
||||||
|
_writeBuffer.appendText(_params._basicAuth);
|
||||||
|
_writeBuffer.appendText(TRI_CHAR_LENGTH_PAIR("\r\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& header : headers) {
|
for (auto const& header : headers) {
|
||||||
|
@ -682,8 +685,11 @@ void SimpleHttpClient::processHeader() {
|
||||||
// found content-length header in response
|
// found content-length header in response
|
||||||
else if (_result->hasContentLength() && _result->getContentLength() > 0) {
|
else if (_result->hasContentLength() && _result->getContentLength() > 0) {
|
||||||
if (_result->getContentLength() > _params._maxPacketSize) {
|
if (_result->getContentLength() > _params._maxPacketSize) {
|
||||||
std::string errorMessage("ignoring HTTP response with 'Content-Length' bigger than max packet size (");
|
std::string errorMessage(
|
||||||
errorMessage += std::to_string(_result->getContentLength()) + " > " + std::to_string(_params._maxPacketSize) + ")";
|
"ignoring HTTP response with 'Content-Length' bigger than max "
|
||||||
|
"packet size (");
|
||||||
|
errorMessage += std::to_string(_result->getContentLength()) + " > " +
|
||||||
|
std::to_string(_params._maxPacketSize) + ")";
|
||||||
setErrorMessage(errorMessage, true);
|
setErrorMessage(errorMessage, true);
|
||||||
|
|
||||||
// reset connection
|
// reset connection
|
||||||
|
@ -725,7 +731,6 @@ void SimpleHttpClient::processHeader() {
|
||||||
TRI_ASSERT(ptr == _readBuffer.c_str() + _readBufferOffset);
|
TRI_ASSERT(ptr == _readBuffer.c_str() + _readBufferOffset);
|
||||||
TRI_ASSERT(remain == _readBuffer.length() - _readBufferOffset);
|
TRI_ASSERT(remain == _readBuffer.length() - _readBufferOffset);
|
||||||
pos = static_cast<char const*>(memchr(ptr, '\n', remain));
|
pos = static_cast<char const*>(memchr(ptr, '\n', remain));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -830,8 +835,11 @@ void SimpleHttpClient::processChunkedHeader() {
|
||||||
|
|
||||||
// failed: too many bytes
|
// failed: too many bytes
|
||||||
if (contentLength > _params._maxPacketSize) {
|
if (contentLength > _params._maxPacketSize) {
|
||||||
std::string errorMessage("ignoring HTTP response with 'Content-Length' bigger than max packet size (");
|
std::string errorMessage(
|
||||||
errorMessage += std::to_string(contentLength) + " > " + std::to_string(_params._maxPacketSize) + ")";
|
"ignoring HTTP response with 'Content-Length' bigger than max packet "
|
||||||
|
"size (");
|
||||||
|
errorMessage += std::to_string(contentLength) + " > " +
|
||||||
|
std::to_string(_params._maxPacketSize) + ")";
|
||||||
setErrorMessage(errorMessage, true);
|
setErrorMessage(errorMessage, true);
|
||||||
// reset connection
|
// reset connection
|
||||||
this->close();
|
this->close();
|
||||||
|
@ -883,7 +891,7 @@ void SimpleHttpClient::processChunkedBody() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_readBufferOffset += (size_t)_nextChunkedSize + 2;
|
_readBufferOffset += (size_t)_nextChunkedSize + 2;
|
||||||
|
|
||||||
_state = IN_READ_CHUNKED_HEADER;
|
_state = IN_READ_CHUNKED_HEADER;
|
||||||
processChunkedHeader();
|
processChunkedHeader();
|
||||||
}
|
}
|
||||||
|
@ -987,5 +995,5 @@ std::string SimpleHttpClient::getServerVersion(int* errorCode) {
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
} // namespace httpclient
|
||||||
}
|
} // namespace arangodb
|
||||||
|
|
|
@ -93,10 +93,7 @@ struct SimpleHttpClientParams {
|
||||||
|
|
||||||
void setJwt(std::string const& jwt) { _jwt = jwt; }
|
void setJwt(std::string const& jwt) { _jwt = jwt; }
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
// sets username and password
|
||||||
/// @brief sets username and password
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void setUserNamePassword(char const* prefix,
|
void setUserNamePassword(char const* prefix,
|
||||||
std::string const& username,
|
std::string const& username,
|
||||||
std::string const& password) {
|
std::string const& password) {
|
||||||
|
|
Loading…
Reference in New Issue