From 863306d32aef8e4b169980a7e9bb4495247d7aaa Mon Sep 17 00:00:00 2001 From: badaix Date: Wed, 5 Feb 2025 23:02:40 +0100 Subject: [PATCH] Add "requiresAuthx" functions --- server/authinfo.cpp | 20 ++++++++------ server/authinfo.hpp | 4 +-- server/control_requests.cpp | 47 ++++++++++++++++--------------- server/control_requests.hpp | 55 ++++++++++++++++++++++++++----------- 4 files changed, 75 insertions(+), 51 deletions(-) diff --git a/server/authinfo.cpp b/server/authinfo.cpp index 01493e71..9e287cb1 100644 --- a/server/authinfo.cpp +++ b/server/authinfo.cpp @@ -98,16 +98,16 @@ std::error_code make_error_code(AuthErrc errc) } -AuthInfo::AuthInfo(ServerSettings::Authorization settings) : is_authenticated_(false), settings_(std::move(settings)) +AuthInfo::AuthInfo(ServerSettings::Authorization auth_settings) : is_authenticated_(false), auth_settings_(std::move(auth_settings)) { } ErrorCode AuthInfo::validateUser(const std::string& username, const std::optional& password) const { - auto iter = - std::find_if(settings_.users.begin(), settings_.users.end(), [&](const ServerSettings::Authorization::User& user) { return user.name == username; }); - if (iter == settings_.users.end()) + auto iter = std::find_if(auth_settings_.users.begin(), auth_settings_.users.end(), + [&](const ServerSettings::Authorization::User& user) { return user.name == username; }); + if (iter == auth_settings_.users.end()) return ErrorCode{AuthErrc::unknown_user}; if (password.has_value() && (iter->password != password.value())) return ErrorCode{AuthErrc::wrong_password}; @@ -154,7 +154,7 @@ ErrorCode AuthInfo::authenticateBasic(const std::string& credentials) ErrorCode AuthInfo::authenticateBearer(const std::string& token) { is_authenticated_ = false; - std::ifstream ifs(settings_.ssl.certificate); + std::ifstream ifs(auth_settings_.ssl.certificate); std::string certificate((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); Jwt jwt; if (!jwt.parse(token, certificate)) @@ -187,7 +187,7 @@ ErrorOr AuthInfo::getToken(const std::string& username, const std:: jwt.setIat(now); jwt.setExp(now + 10h); jwt.setSub(username); - std::ifstream ifs(settings_.ssl.certificate_key); + std::ifstream ifs(auth_settings_.ssl.certificate_key); std::string certificate_key((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); if (!ifs.good()) return ErrorCode{std::make_error_code(std::errc::io_error), "Failed to read private key file"}; @@ -215,6 +215,8 @@ bool AuthInfo::isExpired() const bool AuthInfo::isAuthenticated() const { + if (!auth_settings_.enabled) + return true; return is_authenticated_; } @@ -236,14 +238,14 @@ const std::string& AuthInfo::username() const bool AuthInfo::hasPermission(const std::string& resource) const { - if (!settings_.enabled) + if (!auth_settings_.enabled) return true; if (!isAuthenticated()) return false; - const auto& user_iter = std::find_if(settings_.users.begin(), settings_.users.end(), [&](const auto& user) { return user.name == username_; }); - if (user_iter == settings_.users.end()) + const auto& user_iter = std::find_if(auth_settings_.users.begin(), auth_settings_.users.end(), [&](const auto& user) { return user.name == username_; }); + if (user_iter == auth_settings_.users.end()) return false; const auto& role = user_iter->role; diff --git a/server/authinfo.hpp b/server/authinfo.hpp index 28abc617..84968869 100644 --- a/server/authinfo.hpp +++ b/server/authinfo.hpp @@ -66,7 +66,7 @@ class AuthInfo { public: /// c'tor - explicit AuthInfo(ServerSettings::Authorization settings); + explicit AuthInfo(ServerSettings::Authorization auth_settings); // explicit AuthInfo(std::string authheader); /// d'tor virtual ~AuthInfo() = default; @@ -99,7 +99,7 @@ private: /// optional token expiration std::optional expires_; /// server configuration - ServerSettings::Authorization settings_; + ServerSettings::Authorization auth_settings_; /// Validate @p username and @p password /// @return true if username and password are correct diff --git a/server/control_requests.cpp b/server/control_requests.cpp index 4b3f028a..37c1b716 100644 --- a/server/control_requests.cpp +++ b/server/control_requests.cpp @@ -55,9 +55,13 @@ Request::Request(const Server& server, const std::string& method) : server_(serv bool Request::hasPermission(const AuthInfo& authinfo) const { - bool has_permission = authinfo.hasPermission(method()); - LOG(INFO, LOG_TAG) << "Has permission for '" << method() << "': " << has_permission << "\n"; - return has_permission; + if (!requiresAuthentication() && !requiresAuthorization()) + return true; + + if (requiresAuthentication() && !authinfo.isAuthenticated()) + return false; + + return authinfo.hasPermission(method()); } const std::string& Request::method() const @@ -81,6 +85,15 @@ const ServerSettings& Request::getSettings() const return server_.settings_; } +bool Request::requiresAuthentication() const +{ + return true; +} + +bool Request::requiresAuthorization() const +{ + return true; +} ControlRequestFactory::ControlRequestFactory(const Server& server) @@ -891,6 +904,7 @@ void ServerAuthenticateRequest::execute(const jsonrpcpp::request_ptr& request, A on_response(std::move(response), nullptr); } + #if 0 ServerGetTokenRequest::ServerGetTokenRequest(const Server& server) : Request(server, "Server.GetToken") { @@ -936,43 +950,28 @@ void GeneralGetRpcCommands::execute(const jsonrpcpp::request_ptr& request, AuthI { // clang-format off // Request: {"id":8,"jsonrpc":"2.0","method":"General.GetRPCCommands"} - // Response: {"id":8,"jsonrpc":"2.0","result":{"major":2,"minor":0,"patch":0}} + // Response: TODO // clang-format on - std::ignore = request; - std::ignore = authinfo; - std::ignore = on_response; - Json result; Json commands = Json::array(); - for (const auto& req : requests_) { Json jreq; jreq["method"] = req->method(); jreq["hasPermission"] = req->hasPermission(authinfo); + Json jperms; + jperms["authentication"] = req->requiresAuthentication(); + jperms["authorization"] = req->requiresAuthorization(); + jreq["requires"] = jperms; commands.push_back(jreq); } + Json result; result["commands"] = commands; - // for (const auto& [key, value]: request_map_) - // { - // key - // } - // // : backwards incompatible change - // result["major"] = 23; - // // : feature addition to the API - // result["minor"] = 0; - // // : bugfix release - // result["patch"] = 0; auto response = std::make_shared(*request, result); on_response(std::move(response), nullptr); } -bool GeneralGetRpcCommands::hasPermission(const AuthInfo& authinfo) const -{ - return authinfo.isAuthenticated(); -} - void GeneralGetRpcCommands::setCommands(std::vector> requests) { diff --git a/server/control_requests.hpp b/server/control_requests.hpp index 428a03e7..6db5abd8 100644 --- a/server/control_requests.hpp +++ b/server/control_requests.hpp @@ -57,6 +57,11 @@ public: /// @return true if the user has the permission for the request virtual bool hasPermission(const AuthInfo& authinfo) const; + /// @return user needs to be authenticated + virtual bool requiresAuthentication() const; + /// @return user needs authorization + virtual bool requiresAuthorization() const; + /// @return the name of the method const std::string& method() const; @@ -68,7 +73,6 @@ protected: /// @return server settings const ServerSettings& getSettings() const; - private: /// the server const Server& server_; @@ -309,23 +313,16 @@ public: /// c'tor explicit ServerAuthenticateRequest(const Server& server); void execute(const jsonrpcpp::request_ptr& request, AuthInfo& authinfo, const OnResponse& on_response) override; -}; + bool requiresAuthentication() const override + { + return false; + } -/// "General.GetRpcCommands" request -class GeneralGetRpcCommands : public Request -{ -public: - /// c'tor - explicit GeneralGetRpcCommands(const Server& server); - void execute(const jsonrpcpp::request_ptr& request, AuthInfo& authinfo, const OnResponse& on_response) override; - bool hasPermission(const AuthInfo& authinfo) const override; - - /// Set available @p requests - void setCommands(std::vector> requests); - -private: - std::vector> requests_; + bool requiresAuthorization() const override + { + return false; + } }; @@ -339,3 +336,29 @@ public: void execute(const jsonrpcpp::request_ptr& request, AuthInfo& authinfo, const OnResponse& on_response) override; }; #endif + + +/// "General.GetRpcCommands" request +class GeneralGetRpcCommands : public Request +{ +public: + /// c'tor + explicit GeneralGetRpcCommands(const Server& server); + void execute(const jsonrpcpp::request_ptr& request, AuthInfo& authinfo, const OnResponse& on_response) override; + + /// Set available @p requests + void setCommands(std::vector> requests); + + bool requiresAuthentication() const override + { + return true; + } + + bool requiresAuthorization() const override + { + return false; + } + +private: + std::vector> requests_; +};