Commit f7a7e9f6 authored by jan.koester's avatar jan.koester
Browse files

test

parent e10e8350
Loading
Loading
Loading
Loading
+5 −2
Changes for scripts/authdb-bootstrap.sh: 5 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -10,8 +10,10 @@
#   proxyplus.auditor          proxyplus.readonly_operator
#   proxyplus.http_proxy_user  proxyplus.smtp_relay_user
#
# Usage: authdb-bootstrap.sh <authdb-url> <admin-username> <data-dir>
# Usage: [CLIENT_NAME=<name>] authdb-bootstrap.sh <authdb-url> <admin-username> <data-dir>
# Example: authdb-bootstrap.sh http://127.0.0.1:8080/api/<domainid> admin /var/lib/proxyplus
# CLIENT_NAME names ProxyPlus's service client in authdb (default: proxyplus-service); if
# that name is taken, proxyplus-bootstrap asks for another one.

set -eu

@@ -30,4 +32,5 @@ mkdir -p "$DATA_DIR"
# Creates the proxyplus-service Client-Credential, creates one authdb GPO per permission in
# docs/ROLES.md, and registers permission->GPO-id into ProxyPlus's own ConfigStore at
# $DATA_DIR -- see tools/proxyplus-bootstrap.cpp for exactly what each step does.
exec ./proxyplus-bootstrap "$AUTHDB_URL" "$ADMIN_USER" "$ADMIN_PASSWORD" "$DATA_DIR"
exec ./proxyplus-bootstrap ${CLIENT_NAME:+--client-name "$CLIENT_NAME"} \
    "$AUTHDB_URL" "$ADMIN_USER" "$ADMIN_PASSWORD" "$DATA_DIR"
+59 −8
Changes for tools/proxyplus-bootstrap.cpp: 59 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -15,14 +15,23 @@
//      ProxyPlus's own binary ConfigStore at <data-dir> (never into authdb itself).
//
// Usage:
//   proxyplus-bootstrap <authdb-url> <admin-username> <admin-password> <data-dir>
//   proxyplus-bootstrap [--insecure] [--client-name <name>]
//                       <authdb-url> <admin-username> <admin-password> <data-dir>
//
// The service client is named "proxyplus-service" unless --client-name says otherwise.
// If authdb already has a client of that name (an earlier run, another ProxyPlus instance),
// the tool asks for another one when run on a terminal, and aborts otherwise.

#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <vector>

#include <unistd.h>

#include <authdb/client.h>
#include <uuidp.h>

@@ -111,27 +120,56 @@ const std::vector<PermissionSpec> kPermissions = {
     {"proxyplus.super_admin", "proxyplus.security_admin"}},
};

// authdb's addConnection() error for a taken client name ("Create Client: Clientname
// already Exists aborting!"), matched loosely so a reworded message still counts.
bool isNameTaken(const std::string &error) {
    std::string lower(error);
    std::transform(lower.begin(), lower.end(), lower.begin(),
                   [](unsigned char c) { return std::tolower(c); });
    return lower.find("already exist") != std::string::npos;
}

// Asks for another client name on the terminal; empty if there is none (not
// interactive, EOF, or an empty answer).
std::string askOtherClientName(const std::string &taken) {
    if (!isatty(STDIN_FILENO)) return "";
    std::cerr << "authdb already has a client named '" << taken << "'." << std::endl
              << "Another name for this ProxyPlus service client (empty to abort): " << std::flush;
    std::string name;
    if (!std::getline(std::cin, name)) return "";
    name.erase(0, name.find_first_not_of(" \t"));
    name.erase(name.find_last_not_of(" \t\r") + 1);
    return name;
}

} // namespace

int main(int argc, char **argv) {
    // --insecure may appear anywhere among the positional args; strip it out first so the
    // remaining argv indices below stay fixed regardless of where the caller put it.
    // The options may appear anywhere among the positional args; strip them out first so the
    // remaining argv indices below stay fixed regardless of where the caller put them.
    std::vector<std::string> args;
    bool tlsVerify = true;
    std::string serviceClientName = "proxyplus-service";
    for (int i = 1; i < argc; ++i) {
        if (std::string(argv[i]) == "--insecure") {
        std::string arg = argv[i];
        if (arg == "--insecure") {
            tlsVerify = false;
        } else if (arg == "--client-name" && i + 1 < argc) {
            serviceClientName = argv[++i];
        } else {
            args.push_back(argv[i]);
            args.push_back(arg);
        }
    }

    if (args.size() < 4) {
    if (args.size() < 4 || serviceClientName.empty()) {
        std::cerr << "usage: " << argv[0]
                  << " [--insecure] <authdb-url> <admin-username> <admin-password> <data-dir>"
                  << " [--insecure] [--client-name <name>]"
                     " <authdb-url> <admin-username> <admin-password> <data-dir>"
                  << std::endl;
        std::cerr << "  --insecure     skip TLS peer verification (needed when authdb is reached"
                     " by an IP not covered by its certificate's SAN)" << std::endl;
        std::cerr << "  --client-name  name of the service client to create in authdb"
                     " (default: proxyplus-service)" << std::endl;
        return 1;
    }
    std::string url = args[0], username = args[1], password = args[2], dataDir = args[3];
@@ -153,18 +191,31 @@ int main(int argc, char **argv) {
        return 1;
    }

    const std::string serviceClientName = "proxyplus-service";
    uuid::uuid secretSeed;
    secretSeed.generate();
    std::string serviceClientSecret = secretSeed.c_str();

    std::string clientId;
    for (;;) {
        try {
            clientId = admin.addConnection(serviceClientName, serviceClientSecret);
            break;
        } catch (const std::exception &e) {
            if (isNameTaken(e.what())) {
                std::string other = askOtherClientName(serviceClientName);
                if (!other.empty()) {
                    serviceClientName = other;
                    continue;
                }
                std::cerr << "addConnection failed: client name '" << serviceClientName
                          << "' already exists in authdb -- choose another with --client-name"
                          << std::endl;
                return 1;
            }
            std::cerr << "addConnection failed: " << e.what() << std::endl;
            return 1;
        }
    }
    std::cerr << "created service client '" << serviceClientName << "' (id=" << clientId << ")"
              << std::endl;