2021-01-25 00:24:31 +01:00
|
|
|
#include "./authentication.h"
|
|
|
|
|
|
|
|
#include "./helper.h"
|
|
|
|
#include "./serversetup.h"
|
|
|
|
|
|
|
|
#include <c++utilities/conversion/stringconversion.h>
|
|
|
|
#include <c++utilities/io/ansiescapecodes.h>
|
|
|
|
|
|
|
|
#include <openssl/sha.h>
|
2024-02-21 20:43:38 +01:00
|
|
|
#include <openssl/crypto.h>
|
2021-01-25 00:24:31 +01:00
|
|
|
|
|
|
|
namespace LibRepoMgr {
|
|
|
|
|
|
|
|
template <> inline void convertValue(const std::multimap<std::string, std::string> &multimap, const std::string &key, UserPermissions &result)
|
|
|
|
{
|
|
|
|
using namespace std;
|
|
|
|
using namespace CppUtilities::EscapeCodes;
|
|
|
|
|
|
|
|
const auto value = getLastValueSv(multimap, key);
|
|
|
|
if (!value.has_value()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = UserPermissions::None;
|
|
|
|
const auto parts = CppUtilities::splitStringSimple<std::vector<std::string_view>>(value.value(), " "sv);
|
|
|
|
for (const auto &part : parts) {
|
|
|
|
if (part.empty()) {
|
|
|
|
} else if (part == "read_build_actions_details") {
|
|
|
|
result = result | UserPermissions::ReadBuildActionsDetails;
|
2022-03-10 23:19:02 +01:00
|
|
|
} else if (part == "download_artefacts") {
|
|
|
|
result = result | UserPermissions::DownloadArtefacts;
|
2021-01-25 00:24:31 +01:00
|
|
|
} else if (part == "modify_build_actions") {
|
|
|
|
result = result | UserPermissions::ModifyBuildActions;
|
|
|
|
} else if (part == "perform_admin_actions") {
|
|
|
|
result = result | UserPermissions::PerformAdminActions;
|
|
|
|
} else {
|
|
|
|
std::cerr << Phrases::Error << "Specified permission \"" << part << "\" for key \"" << key << "\" is invalid." << Phrases::End;
|
|
|
|
std::exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-21 20:43:38 +01:00
|
|
|
static constexpr char toUpper(const char c)
|
|
|
|
{
|
|
|
|
return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;
|
|
|
|
}
|
|
|
|
|
2021-01-25 00:24:31 +01:00
|
|
|
void ServiceSetup::Authentication::applyConfig(const std::string &userName, const std::multimap<std::string, std::string> &multimap)
|
|
|
|
{
|
|
|
|
auto &user = users[userName];
|
|
|
|
convertValue(multimap, "password_sha512", user.passwordSha512);
|
|
|
|
convertValue(multimap, "permissions", user.permissions);
|
2024-02-21 20:43:38 +01:00
|
|
|
for (auto &c : user.passwordSha512) {
|
|
|
|
c = toUpper(c);
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
2022-07-10 17:18:29 +02:00
|
|
|
UserAuth ServiceSetup::Authentication::authenticate(std::string_view authorizationHeader) const
|
2021-01-25 00:24:31 +01:00
|
|
|
{
|
|
|
|
// extract user name and password from base64 encoded header value
|
2022-07-10 17:18:29 +02:00
|
|
|
auto auth = UserAuth();
|
2021-01-25 00:24:31 +01:00
|
|
|
if (!CppUtilities::startsWith(authorizationHeader, "Basic ") && authorizationHeader.size() < 100) {
|
2022-07-10 17:18:29 +02:00
|
|
|
return auth;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
std::pair<std::unique_ptr<std::uint8_t[]>, std::uint32_t> data;
|
|
|
|
try {
|
|
|
|
data = CppUtilities::decodeBase64(authorizationHeader.data() + 6, static_cast<std::uint32_t>(authorizationHeader.size() - 6));
|
|
|
|
} catch (const CppUtilities::ConversionException &) {
|
2022-07-10 17:18:29 +02:00
|
|
|
return auth;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
const auto parts = CppUtilities::splitStringSimple<std::vector<std::string_view>>(
|
|
|
|
std::string_view(reinterpret_cast<const char *>(data.first.get()), data.second), ":", 2);
|
|
|
|
if (parts.size() != 2) {
|
2022-07-10 17:18:29 +02:00
|
|
|
return auth;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// find relevant user
|
|
|
|
const std::string_view userName = parts[0], password = parts[1];
|
|
|
|
if (userName.empty() || password.empty()) {
|
2022-07-10 17:18:29 +02:00
|
|
|
return auth;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
if (userName == "try" && password == "again") {
|
2022-07-10 17:18:29 +02:00
|
|
|
auth.permissions = UserPermissions::TryAgain;
|
|
|
|
return auth;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
const auto user = users.find(std::string(userName));
|
|
|
|
if (user == users.cend()) {
|
2022-07-10 17:18:29 +02:00
|
|
|
return auth;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
2024-02-21 20:43:38 +01:00
|
|
|
constexpr auto sha512HexSize = SHA512_DIGEST_LENGTH * 2;
|
2021-01-25 00:24:31 +01:00
|
|
|
if (user->second.passwordSha512.size() != sha512HexSize) {
|
2022-07-10 17:18:29 +02:00
|
|
|
return auth;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// hash password
|
2024-02-21 20:43:38 +01:00
|
|
|
auto hash = std::array<unsigned char, SHA512_DIGEST_LENGTH>();
|
|
|
|
SHA512(reinterpret_cast<const unsigned char *>(password.data()), password.size(), hash.data());
|
|
|
|
|
|
|
|
// convert hash to string (hexadecimal)
|
|
|
|
auto hashHex = std::array<char, sha512HexSize>();
|
|
|
|
auto hashHexIter = hashHex.begin();
|
|
|
|
for (const auto hashNumber : hash) {
|
|
|
|
*(hashHexIter++) = static_cast<char>(CppUtilities::digitToChar((hashNumber / 16) % 16));
|
|
|
|
*(hashHexIter++) = static_cast<char>(CppUtilities::digitToChar(hashNumber % 16));
|
|
|
|
}
|
2021-01-25 00:24:31 +01:00
|
|
|
|
|
|
|
// check whether password hash matches
|
2024-02-21 20:43:38 +01:00
|
|
|
if (CRYPTO_memcmp(user->second.passwordSha512.data(), hashHex.data(), sha512HexSize) != 0) {
|
|
|
|
return auth;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// return the user's permissions
|
2022-07-10 17:18:29 +02:00
|
|
|
auth.permissions = user->second.permissions;
|
|
|
|
auth.name = userName;
|
|
|
|
auth.password = password;
|
|
|
|
return auth;
|
2021-01-25 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace LibRepoMgr
|