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

key support

parent efd9c59f
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -19,4 +19,5 @@ AUTHDB:
        PATH: "/tmp/cluster.db"
    ADMINDB:
        PATH: "/tmp/admin.db"
    ADMIN_KEY: "changeme-authdb-admin-key"
    VACUUM_INTERVAL: 6
+126 −2
Original line number Diff line number Diff line
@@ -146,6 +146,10 @@ namespace authdb {
            _DomainCacheEvictor = std::move(evictor);
        }

        void setAdminKey(const std::string &key) {
            _AdminKey = key;
        }

        /* ---- JSON API: List Users ---- */
        void apiListUsers(libhttppp::HttpRequest &curreq, const char *cdid) {
            AuthBackend *backend = getDomain(cdid);
@@ -805,7 +809,7 @@ namespace authdb {

        /* ---- JSON API: Create Domain ---- */
        void apiCreateDomain(libhttppp::HttpRequest &curreq, const SessionData *sdat) {
            if (!isSuperAdmin(sdat))
            if (sdat && !isSuperAdmin(sdat))
                throw AuthBackendError("createDomain: nur SuperAdmins von admin.local erlaubt!");
            std::vector<char> body;
            libhttppp::HttpForm curform;
@@ -936,7 +940,7 @@ namespace authdb {

        /* ---- JSON API: Remove Domain ---- */
        void apiRemoveDomain(libhttppp::HttpRequest &curreq, const char *cdid, const SessionData *sdat) {
            if (!isSuperAdmin(sdat))
            if (sdat && !isSuperAdmin(sdat))
                throw AuthBackendError("removeDomain: nur SuperAdmins von admin.local erlaubt!");

            // Purge domain backend cluster data before removing the domain record
@@ -1969,8 +1973,26 @@ namespace authdb {
            libhttppp::HttpCookie cookie;
            const SessionData *sdat = nullptr;
            uuid::uuid ssid;
            bool apiKeyAuth = false;

            // Check for API key authentication (Bearer token)
            if (!_AdminKey.empty()) {
                libhttppp::HttpHeader::HeaderData *authHeader = curreq.getHeaderData("authorization");
                if (authHeader && authHeader->getfirstValue()) {
                    std::string authVal = authHeader->getfirstValue()->getvalue();
                    std::string key;
                    if (authVal.size() > 7 && authVal.substr(0, 7) == "Bearer ")
                        key = authVal.substr(7);
                    else if (authVal.size() > 7 && authVal.substr(0, 7) == "ApiKey ")
                        key = authVal.substr(7);
                    if (!key.empty() && key == _AdminKey) {
                        apiKeyAuth = true;
                    }
                }
            }

            try {
                if (!apiKeyAuth) {
                cookie.parse(curreq);
                for (libhttppp::HttpCookie::CookieData *cur = cookie.getfirstCookieData(); cur; cur = cur->nextCookieData()) {
                    std::cerr << "[CTRL] cookie: key='" << cur->getKey() << "' val='" << cur->getValue() << "'" << std::endl;
@@ -2006,6 +2028,7 @@ namespace authdb {
                if (!sdat) {
                    throw AuthBackendError("No Session found!");
                }
                } // end if (!apiKeyAuth)
            } catch (...) {
                // If cluster is critical (< k nodes), show warning page with auto-refresh
                if (g_Cluster && g_Cluster->isCritical()) {
@@ -2089,6 +2112,102 @@ namespace authdb {
            // Check for /settings/{domain}/api/{action}[/{param}]
            if (sscanf(url.c_str(), "/settings/%[^/]/api/%[^/]/%s", domain, apiurl, param) >= 2) {
                try {
                    // API key auth bypasses all permission checks (SuperAdmin)
                    if (apiKeyAuth) {
                        // Route API key requests without permission checks
                        if (strcmp(apiurl, "listusers") == 0) {
                            apiListUsers(curreq, domain);
                        } else if (strcmp(apiurl, "getuser") == 0 && param[0]) {
                            apiGetUser(curreq, domain, param);
                        } else if (strcmp(apiurl, "createuser") == 0) {
                            apiCreateUser(curreq, domain);
                        } else if (strcmp(apiurl, "removeuser") == 0 && param[0]) {
                            apiRemoveUser(curreq, domain, param);
                        } else if (strcmp(apiurl, "edituser") == 0 && param[0]) {
                            apiEditUser(curreq, domain, param);
                        } else if (strcmp(apiurl, "listdomains") == 0) {
                            apiListDomains(curreq);
                        } else if (strcmp(apiurl, "checkpermissions") == 0) {
                            // Return SuperAdmin permissions for API key
                            json_object *jobj = json_object_new_object();
                            json_object_object_add(jobj, "superadmin", json_object_new_boolean(true));
                            json_object_object_add(jobj, "sessiondomain", json_object_new_string("admin"));
                            json_object *jgpo = json_object_new_object();
                            for (size_t i = 0; gpo_default[i][0] != nullptr; ++i)
                                json_object_object_add(jgpo, gpo_default[i][0], json_object_new_boolean(true));
                            json_object_object_add(jobj, "gpo", jgpo);
                            json_object_object_add(jobj, "backendtype", json_object_new_int(_AdminBackend.getType()));
                            json_object_object_add(jobj, "cluster", json_object_new_boolean(g_Cluster && g_Cluster->isRunning()));
                            sendJson(curreq, jobj);
                            json_object_put(jobj);
                        } else if (strcmp(apiurl, "createdomain") == 0) {
                            apiCreateDomain(curreq, nullptr);
                        } else if (strcmp(apiurl, "removedomain") == 0 && param[0]) {
                            apiRemoveDomain(curreq, param, nullptr);
                        } else if (strcmp(apiurl, "listgroups") == 0) {
                            apiListGroups(curreq, domain);
                        } else if (strcmp(apiurl, "getgroup") == 0 && param[0]) {
                            apiGetGroup(curreq, domain, param);
                        } else if (strcmp(apiurl, "creategroup") == 0) {
                            apiCreateGroup(curreq, domain);
                        } else if (strcmp(apiurl, "removegroup") == 0 && param[0]) {
                            apiRemoveGroup(curreq, domain, param);
                        } else if (strcmp(apiurl, "editgroup") == 0 && param[0]) {
                            apiEditGroup(curreq, domain, param);
                        } else if (strcmp(apiurl, "listsessions") == 0) {
                            apiListSessions(curreq, domain);
                        } else if (strcmp(apiurl, "removesession") == 0 && param[0]) {
                            apiRemoveSession(curreq, param);
                        } else if (strcmp(apiurl, "reloadsession") == 0 && param[0]) {
                            apiReloadSession(curreq, domain, param);
                        } else if (strcmp(apiurl, "listgpos") == 0) {
                            apiListGpos(curreq, domain);
                        } else if (strcmp(apiurl, "getgpo") == 0 && param[0]) {
                            apiGetGpo(curreq, domain, param);
                        } else if (strcmp(apiurl, "creategpo") == 0) {
                            apiCreateGpo(curreq, domain);
                        } else if (strcmp(apiurl, "removegpo") == 0 && param[0]) {
                            apiRemoveGpo(curreq, domain, param);
                        } else if (strcmp(apiurl, "editgpo") == 0 && param[0]) {
                            apiEditGpo(curreq, domain, param);
                        } else if (strcmp(apiurl, "listclients") == 0) {
                            apiListClients(curreq, domain);
                        } else if (strcmp(apiurl, "getclient") == 0 && param[0]) {
                            apiGetClient(curreq, domain, param);
                        } else if (strcmp(apiurl, "createclient") == 0) {
                            apiCreateClient(curreq, domain);
                        } else if (strcmp(apiurl, "removeclient") == 0 && param[0]) {
                            apiRemoveClient(curreq, domain, param);
                        } else if (strcmp(apiurl, "editclient") == 0 && param[0]) {
                            apiEditClient(curreq, domain, param);
                        } else if (strcmp(apiurl, "listservices") == 0) {
                            apiListServices(curreq, domain);
                        } else if (strcmp(apiurl, "getservice") == 0 && param[0]) {
                            apiGetService(curreq, domain, param);
                        } else if (strcmp(apiurl, "createservice") == 0) {
                            apiCreateService(curreq, domain);
                        } else if (strcmp(apiurl, "removeservice") == 0 && param[0]) {
                            apiRemoveService(curreq, domain, param);
                        } else if (strcmp(apiurl, "editservice") == 0 && param[0]) {
                            apiEditService(curreq, domain, param);
                        } else if (strcmp(apiurl, "export") == 0) {
                            apiExportDb(curreq, domain);
                        } else if (strcmp(apiurl, "import") == 0) {
                            apiImportDb(curreq, domain);
                        } else if (strcmp(apiurl, "vacuum") == 0) {
                            apiVacuum(curreq, domain);
                        } else if (strcmp(apiurl, "clusterstatus") == 0) {
                            apiClusterStatus(curreq);
                        } else if (strcmp(apiurl, "clusterscrub") == 0) {
                            apiClusterScrub(curreq);
                        } else if (strcmp(apiurl, "clusterrebalance") == 0) {
                            apiClusterRebalance(curreq);
                        } else {
                            sendJsonError(curreq, "Unknown API endpoint", 404);
                        }
                        return;
                    }

                    if (strcmp(apiurl, "listusers") == 0) {
                        checkDomainAccess(sdat, domain);
                        checkGPO(sdat, "a1b2c3d4-452e-11f0-b1cc-1a2b3c4d5e02");
@@ -2251,6 +2370,7 @@ namespace authdb {
        std::vector<char> _AdminHtml;
        std::function<AuthBackend*(const char*)> _DomainResolver;
        std::function<void(const char*)> _DomainCacheEvictor;
        std::string _AdminKey;
    };

    AdminInterface::AdminInterface(AuthBackend &bck, std::vector<netplus::socket*> ssock) : _bck(bck) {
@@ -2269,6 +2389,10 @@ namespace authdb {
        _ctl->setDomainCacheEvictor(std::move(evictor));
    }

    void AdminInterface::setAdminKey(const std::string &key) {
        _ctl->setAdminKey(key);
    }

    void AdminInterface::Request(libhttppp::HttpRequest &curreq, const int tid, ULONG_PTR args) {
        if (curreq.getRequestURL().compare(0, 9, "/settings", 9) == 0) {
            _ctl->SettingsController(curreq, tid, args);
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ namespace authdb {
        void Request(libhttppp::HttpRequest &curreq, const int tid, ULONG_PTR args);
        void setDomainResolver(std::function<AuthBackend*(const char*)> resolver);
        void setDomainCacheEvictor(std::function<void(const char*)> evictor);
        void setAdminKey(const std::string &key);
    public:
        AdminController                            * _ctl;
        AuthBackend                                 &_bck;
+14 −0
Original line number Diff line number Diff line
@@ -126,6 +126,10 @@ namespace authdb {
            });
        };

        void setAdminKey(const std::string &key) {
            _AdminInterface.setAdminKey(key);
        }

        void WizzardEvent(libhttppp::HttpRequest &curreq, const int tid, ULONG_PTR args){
            std::lock_guard<std::mutex> wlock(g_wizzard);

@@ -806,6 +810,16 @@ int main(int argc,char *argv[]){

        authdb::AuthDB authdb(backend,httpd.getServerSockets());

        // Set admin API key if configured
        auto *adminKeyNode = config.getKey("/AUTHDB/ADMIN_KEY");
        if (adminKeyNode) {
            std::string adminKey = config.getValue(adminKeyNode, 0);
            if (!adminKey.empty()) {
                authdb.setAdminKey(adminKey);
                std::cerr << "[AUTHDB] Admin API key authentication enabled" << std::endl;
            }
        }

        // Pre-load all domain backends into cache so API requests
        // don't need to lock the admin backend for domain resolution.
        if (backend.end() > sizeof(authdb::AuthHeader))