Add "requiresAuthx" functions

This commit is contained in:
badaix 2025-02-05 23:02:40 +01:00
parent f44a04f2c9
commit 863306d32a
4 changed files with 75 additions and 51 deletions

View file

@ -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<std::string>& 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<char>(ifs)), std::istreambuf_iterator<char>());
Jwt jwt;
if (!jwt.parse(token, certificate))
@ -187,7 +187,7 @@ ErrorOr<std::string> 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<char>(ifs)), std::istreambuf_iterator<char>());
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;

View file

@ -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<std::chrono::system_clock::time_point> expires_;
/// server configuration
ServerSettings::Authorization settings_;
ServerSettings::Authorization auth_settings_;
/// Validate @p username and @p password
/// @return true if username and password are correct

View file

@ -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
// }
// // <major>: backwards incompatible change
// result["major"] = 23;
// // <minor>: feature addition to the API
// result["minor"] = 0;
// // <patch>: bugfix release
// result["patch"] = 0;
auto response = std::make_shared<jsonrpcpp::Response>(*request, result);
on_response(std::move(response), nullptr);
}
bool GeneralGetRpcCommands::hasPermission(const AuthInfo& authinfo) const
{
return authinfo.isAuthenticated();
}
void GeneralGetRpcCommands::setCommands(std::vector<std::shared_ptr<Request>> requests)
{

View file

@ -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<std::shared_ptr<Request>> requests);
private:
std::vector<std::shared_ptr<Request>> 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<std::shared_ptr<Request>> requests);
bool requiresAuthentication() const override
{
return true;
}
bool requiresAuthorization() const override
{
return false;
}
private:
std::vector<std::shared_ptr<Request>> requests_;
};