mirror of
https://github.com/badaix/snapcast.git
synced 2025-04-29 18:27:12 +02:00
Add "requiresAuthx" functions
This commit is contained in:
parent
f44a04f2c9
commit
863306d32a
4 changed files with 75 additions and 51 deletions
|
@ -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
|
ErrorCode AuthInfo::validateUser(const std::string& username, const std::optional<std::string>& password) const
|
||||||
{
|
{
|
||||||
auto iter =
|
auto iter = std::find_if(auth_settings_.users.begin(), auth_settings_.users.end(),
|
||||||
std::find_if(settings_.users.begin(), settings_.users.end(), [&](const ServerSettings::Authorization::User& user) { return user.name == username; });
|
[&](const ServerSettings::Authorization::User& user) { return user.name == username; });
|
||||||
if (iter == settings_.users.end())
|
if (iter == auth_settings_.users.end())
|
||||||
return ErrorCode{AuthErrc::unknown_user};
|
return ErrorCode{AuthErrc::unknown_user};
|
||||||
if (password.has_value() && (iter->password != password.value()))
|
if (password.has_value() && (iter->password != password.value()))
|
||||||
return ErrorCode{AuthErrc::wrong_password};
|
return ErrorCode{AuthErrc::wrong_password};
|
||||||
|
@ -154,7 +154,7 @@ ErrorCode AuthInfo::authenticateBasic(const std::string& credentials)
|
||||||
ErrorCode AuthInfo::authenticateBearer(const std::string& token)
|
ErrorCode AuthInfo::authenticateBearer(const std::string& token)
|
||||||
{
|
{
|
||||||
is_authenticated_ = false;
|
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>());
|
std::string certificate((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||||
Jwt jwt;
|
Jwt jwt;
|
||||||
if (!jwt.parse(token, certificate))
|
if (!jwt.parse(token, certificate))
|
||||||
|
@ -187,7 +187,7 @@ ErrorOr<std::string> AuthInfo::getToken(const std::string& username, const std::
|
||||||
jwt.setIat(now);
|
jwt.setIat(now);
|
||||||
jwt.setExp(now + 10h);
|
jwt.setExp(now + 10h);
|
||||||
jwt.setSub(username);
|
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>());
|
std::string certificate_key((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||||
if (!ifs.good())
|
if (!ifs.good())
|
||||||
return ErrorCode{std::make_error_code(std::errc::io_error), "Failed to read private key file"};
|
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
|
bool AuthInfo::isAuthenticated() const
|
||||||
{
|
{
|
||||||
|
if (!auth_settings_.enabled)
|
||||||
|
return true;
|
||||||
return is_authenticated_;
|
return is_authenticated_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,14 +238,14 @@ const std::string& AuthInfo::username() const
|
||||||
|
|
||||||
bool AuthInfo::hasPermission(const std::string& resource) const
|
bool AuthInfo::hasPermission(const std::string& resource) const
|
||||||
{
|
{
|
||||||
if (!settings_.enabled)
|
if (!auth_settings_.enabled)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!isAuthenticated())
|
if (!isAuthenticated())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto& user_iter = std::find_if(settings_.users.begin(), settings_.users.end(), [&](const auto& user) { return user.name == username_; });
|
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 == settings_.users.end())
|
if (user_iter == auth_settings_.users.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto& role = user_iter->role;
|
const auto& role = user_iter->role;
|
||||||
|
|
|
@ -66,7 +66,7 @@ class AuthInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// c'tor
|
/// c'tor
|
||||||
explicit AuthInfo(ServerSettings::Authorization settings);
|
explicit AuthInfo(ServerSettings::Authorization auth_settings);
|
||||||
// explicit AuthInfo(std::string authheader);
|
// explicit AuthInfo(std::string authheader);
|
||||||
/// d'tor
|
/// d'tor
|
||||||
virtual ~AuthInfo() = default;
|
virtual ~AuthInfo() = default;
|
||||||
|
@ -99,7 +99,7 @@ private:
|
||||||
/// optional token expiration
|
/// optional token expiration
|
||||||
std::optional<std::chrono::system_clock::time_point> expires_;
|
std::optional<std::chrono::system_clock::time_point> expires_;
|
||||||
/// server configuration
|
/// server configuration
|
||||||
ServerSettings::Authorization settings_;
|
ServerSettings::Authorization auth_settings_;
|
||||||
|
|
||||||
/// Validate @p username and @p password
|
/// Validate @p username and @p password
|
||||||
/// @return true if username and password are correct
|
/// @return true if username and password are correct
|
||||||
|
|
|
@ -55,9 +55,13 @@ Request::Request(const Server& server, const std::string& method) : server_(serv
|
||||||
|
|
||||||
bool Request::hasPermission(const AuthInfo& authinfo) const
|
bool Request::hasPermission(const AuthInfo& authinfo) const
|
||||||
{
|
{
|
||||||
bool has_permission = authinfo.hasPermission(method());
|
if (!requiresAuthentication() && !requiresAuthorization())
|
||||||
LOG(INFO, LOG_TAG) << "Has permission for '" << method() << "': " << has_permission << "\n";
|
return true;
|
||||||
return has_permission;
|
|
||||||
|
if (requiresAuthentication() && !authinfo.isAuthenticated())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return authinfo.hasPermission(method());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& Request::method() const
|
const std::string& Request::method() const
|
||||||
|
@ -81,6 +85,15 @@ const ServerSettings& Request::getSettings() const
|
||||||
return server_.settings_;
|
return server_.settings_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Request::requiresAuthentication() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Request::requiresAuthorization() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ControlRequestFactory::ControlRequestFactory(const Server& server)
|
ControlRequestFactory::ControlRequestFactory(const Server& server)
|
||||||
|
@ -891,6 +904,7 @@ void ServerAuthenticateRequest::execute(const jsonrpcpp::request_ptr& request, A
|
||||||
on_response(std::move(response), nullptr);
|
on_response(std::move(response), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
ServerGetTokenRequest::ServerGetTokenRequest(const Server& server) : Request(server, "Server.GetToken")
|
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
|
// clang-format off
|
||||||
// Request: {"id":8,"jsonrpc":"2.0","method":"General.GetRPCCommands"}
|
// 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
|
// clang-format on
|
||||||
|
|
||||||
std::ignore = request;
|
|
||||||
std::ignore = authinfo;
|
|
||||||
std::ignore = on_response;
|
|
||||||
Json result;
|
|
||||||
Json commands = Json::array();
|
Json commands = Json::array();
|
||||||
|
|
||||||
for (const auto& req : requests_)
|
for (const auto& req : requests_)
|
||||||
{
|
{
|
||||||
Json jreq;
|
Json jreq;
|
||||||
jreq["method"] = req->method();
|
jreq["method"] = req->method();
|
||||||
jreq["hasPermission"] = req->hasPermission(authinfo);
|
jreq["hasPermission"] = req->hasPermission(authinfo);
|
||||||
|
Json jperms;
|
||||||
|
jperms["authentication"] = req->requiresAuthentication();
|
||||||
|
jperms["authorization"] = req->requiresAuthorization();
|
||||||
|
jreq["requires"] = jperms;
|
||||||
commands.push_back(jreq);
|
commands.push_back(jreq);
|
||||||
}
|
}
|
||||||
|
Json result;
|
||||||
result["commands"] = commands;
|
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);
|
auto response = std::make_shared<jsonrpcpp::Response>(*request, result);
|
||||||
on_response(std::move(response), nullptr);
|
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)
|
void GeneralGetRpcCommands::setCommands(std::vector<std::shared_ptr<Request>> requests)
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,6 +57,11 @@ public:
|
||||||
/// @return true if the user has the permission for the request
|
/// @return true if the user has the permission for the request
|
||||||
virtual bool hasPermission(const AuthInfo& authinfo) const;
|
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
|
/// @return the name of the method
|
||||||
const std::string& method() const;
|
const std::string& method() const;
|
||||||
|
|
||||||
|
@ -68,7 +73,6 @@ protected:
|
||||||
/// @return server settings
|
/// @return server settings
|
||||||
const ServerSettings& getSettings() const;
|
const ServerSettings& getSettings() const;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// the server
|
/// the server
|
||||||
const Server& server_;
|
const Server& server_;
|
||||||
|
@ -309,23 +313,16 @@ public:
|
||||||
/// c'tor
|
/// c'tor
|
||||||
explicit ServerAuthenticateRequest(const Server& server);
|
explicit ServerAuthenticateRequest(const Server& server);
|
||||||
void execute(const jsonrpcpp::request_ptr& request, AuthInfo& authinfo, const OnResponse& on_response) override;
|
void execute(const jsonrpcpp::request_ptr& request, AuthInfo& authinfo, const OnResponse& on_response) override;
|
||||||
};
|
|
||||||
|
|
||||||
|
bool requiresAuthentication() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// "General.GetRpcCommands" request
|
bool requiresAuthorization() const override
|
||||||
class GeneralGetRpcCommands : public Request
|
{
|
||||||
{
|
return false;
|
||||||
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_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -339,3 +336,29 @@ public:
|
||||||
void execute(const jsonrpcpp::request_ptr& request, AuthInfo& authinfo, const OnResponse& on_response) override;
|
void execute(const jsonrpcpp::request_ptr& request, AuthInfo& authinfo, const OnResponse& on_response) override;
|
||||||
};
|
};
|
||||||
#endif
|
#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_;
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue