1
0
Fork 0
arangodb/arangod/VocBase/AuthInfo.cpp

317 lines
8.4 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#include "AuthInfo.h"
#include <iostream>
#include <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>
#include "Basics/ReadLocker.h"
#include "Basics/VelocyPackHelper.h"
#include "Basics/WriteLocker.h"
#include "Logger/Logger.h"
#include "RestServer/DatabaseFeature.h"
#include "Utils/SingleCollectionTransaction.h"
#include "Utils/StandaloneTransactionContext.h"
#include "VocBase/MasterPointer.h"
#include "VocBase/collection.h"
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::velocypack;
static AuthEntry CreateAuthEntry(VPackSlice const& slice) {
if (slice.isNone() || !slice.isObject()) {
return AuthEntry();
}
// extract "user" attribute
VPackSlice const userSlice = slice.get("user");
if (!userSlice.isString()) {
LOG(DEBUG) << "cannot extract username";
return AuthEntry();
}
VPackSlice const authDataSlice = slice.get("authData");
if (!authDataSlice.isObject()) {
LOG(DEBUG) << "cannot extract authData";
return AuthEntry();
}
VPackSlice const simpleSlice = authDataSlice.get("simple");
if (!simpleSlice.isObject()) {
LOG(DEBUG) << "cannot extract simple";
return AuthEntry();
}
VPackSlice const methodSlice = simpleSlice.get("method");
VPackSlice const saltSlice = simpleSlice.get("salt");
VPackSlice const hashSlice = simpleSlice.get("hash");
if (!methodSlice.isString() || !saltSlice.isString() ||
!hashSlice.isString()) {
LOG(DEBUG) << "cannot extract password internals";
return AuthEntry();
}
// extract "active" attribute
bool active;
VPackSlice const activeSlice = authDataSlice.get("active");
if (!activeSlice.isBoolean()) {
LOG(DEBUG) << "cannot extract active flag";
return AuthEntry();
}
active = activeSlice.getBool();
// extract "changePassword" attribute
bool mustChange =
VelocyPackHelper::getBooleanValue(slice, "changePassword", false);
std::cout
<< "user: " << userSlice.copyString() << "\n"
<< "method: " << methodSlice.copyString() << "\n"
<< "salt: " << saltSlice.copyString() << "\n"
<< "hash: " << hashSlice.copyString() << "\n"
<< "active: " << active << "\n"
<< "must change: " << mustChange << "\n";
return AuthEntry(userSlice.copyString(), methodSlice.copyString(),
saltSlice.copyString(), hashSlice.copyString(), active,
mustChange);
}
void AuthInfo::clear() {
_authInfo.clear();
_authCache.clear();
}
bool AuthInfo::reload() {
insertInitial();
TRI_vocbase_t* vocbase = DatabaseFeature::DATABASE->vocbase();
if (vocbase == nullptr) {
LOG(DEBUG) << "system database is unknown, cannot load authentication "
<< "and authorization information";
return false;
}
LOG(DEBUG) << "starting to load authentication and authorization information";
WRITE_LOCKER(writeLocker, _authInfoLock);
SingleCollectionTransaction trx(StandaloneTransactionContext::Create(vocbase),
TRI_COL_NAME_USERS, TRI_TRANSACTION_READ);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return false;
}
OperationResult users =
trx.all(TRI_COL_NAME_USERS, 0, UINT64_MAX, OperationOptions());
trx.finish(users.code);
if (users.failed()) {
LOG(ERR) << "cannot read users from _users collection";
return false;
}
auto usersSlice = users.slice();
if (!usersSlice.isArray()) {
LOG(ERR) << "cannot read users from _users collection";
return false;
}
clear();
if (usersSlice.length() == 0) {
insertInitial();
} else {
for (VPackSlice const& userSlice : VPackArrayIterator(usersSlice)) {
AuthEntry auth = CreateAuthEntry(userSlice);
if (auth.isActive()) {
_authInfo[auth.username()] = auth;
}
};
}
return true;
}
std::string AuthInfo::checkCache(std::string const& authorizationField,
bool* mustChange) {
READ_LOCKER(readLocker, _authInfoLock);
auto const& it = _authCache.find(authorizationField);
if (it != _authCache.end()) {
AuthCache const& cached = it->second;
#warning expires
*mustChange = cached.mustChange();
return cached.username();
}
// sorry, not found
return "";
}
bool AuthInfo::canUseDatabase(std::string const& username,
char const* databaseName) {
#warning TODO
#if 0
READ_LOCKER(readLocker, _authInfoLock);
AuthEntry const& entry = findUser(username);
if (!entry.isActive()) {
return false;
}
return entry._databases.find(databaseName) != entry.databases.end();
#endif
return true;
}
AuthResult AuthInfo::checkAuthentication(std::string const& authorizationField,
char const* databaseName) {
return AuthResult();
}
bool AuthInfo::populate(VPackSlice const& slice) {
TRI_ASSERT(slice.isArray());
WRITE_LOCKER(writeLocker, _authInfoLock);
clear();
for (VPackSlice const& authSlice : VPackArrayIterator(slice)) {
AuthEntry auth = CreateAuthEntry(authSlice);
if (auth.isActive()) {
_authInfo.emplace(auth.username(), auth);
}
}
return true;
}
void AuthInfo::insertInitial() {
if (!_authInfo.empty()) {
return;
}
try {
VPackBuilder builder;
builder.openArray();
// The only users object
builder.add(VPackValue(VPackValueType::Object));
// username
builder.add("user", VPackValue("root"));
builder.add("authData", VPackValue(VPackValueType::Object));
// simple auth
builder.add("simple", VPackValue(VPackValueType::Object));
builder.add("method", VPackValue("sha256"));
char const* salt = "c776f5f4";
builder.add("salt", VPackValue(salt));
char const* hash =
"ef74bc6fd59ac713bf5929c5ac2f42233e50d4d58748178132ea46dec433bd5b";
builder.add("hash", VPackValue(hash));
builder.close(); // simple
builder.add("active", VPackValue(true));
builder.add("databases", VPackValue(VPackValueType::Array));
builder.add(VPackValue("*"));
builder.close();
builder.close(); // authData
builder.close(); // The user object
builder.close(); // The Array
populate(builder.slice());
} catch (...) {
// No action
}
}
#if 0
// no entry found in cache, decode the basic auth info and look it up
std::string const up = StringUtils::decodeBase64(auth);
std::string::size_type n = up.find(':', 0);
if (n == std::string::npos || n == 0 || n + 1 > up.size()) {
LOG(TRACE) << "invalid authentication data found, cannot extract "
"username/password";
return GeneralResponse::ResponseCode::BAD;
}
username = up.substr(0, n);
LOG(TRACE) << "checking authentication for user '" << username << "'";
////////////////////////////////////////////////////////////////////////////////
/// @brief check if a user can see a database
/// note: "seeing" here does not necessarily mean the user can access the db.
/// it only means there is a user account (with whatever password) present
/// in the database
////////////////////////////////////////////////////////////////////////////////
static bool CanUseDatabase(TRI_vocbase_t* vocbase, char const* username) {
if (!vocbase->_settings.requireAuthentication) {
// authentication is turned off
return true;
}
if (strlen(username) == 0) {
// will happen if username is "" (when converting it from a null value)
// this will happen if authentication is turned off
return true;
}
return TRI_ExistsAuthenticationAuthInfo(vocbase, username);
}
#endif