Implement OSD-side authorization for operations
This commit is contained in:
+3
-3
@@ -264,9 +264,9 @@ static const char* help_text =
|
||||
" Start HTTP server able to handle CLI commands over a REST API. Options:\n"
|
||||
" --bind_address ADDR Specify server IP address or addresses, separated by space. Default is 127.0.0.1.\n"
|
||||
" --port 8080 Specify server port.\n"
|
||||
" --ssl_cert FILE Path to server SSL certificate file (PEM format).\n"
|
||||
" --ssl_key FILE Path to server SSL private key file.\n"
|
||||
" --ssl_ca FILE Path to file with SSL CA certificates used to validate client connections.\n"
|
||||
" --server_cert FILE Path to server TLS certificate file (PEM format).\n"
|
||||
" --server_key FILE Path to server TLS private key file.\n"
|
||||
" --client_ca FILE Path to file with TLS CA certificates used to validate client connections.\n"
|
||||
"\n"
|
||||
"Use vitastor-cli --help <command> for command details or vitastor-cli --help --all for all details.\n"
|
||||
"\n"
|
||||
|
||||
+2
-7
@@ -27,12 +27,7 @@ struct cli_result_t
|
||||
json11::Json data;
|
||||
};
|
||||
|
||||
struct cli_user_t
|
||||
{
|
||||
std::string name;
|
||||
std::string type;
|
||||
std::set<std::string> groups;
|
||||
};
|
||||
struct user_info_t;
|
||||
|
||||
class cli_tool_t
|
||||
{
|
||||
@@ -45,7 +40,7 @@ public:
|
||||
bool is_command_line = false;
|
||||
bool color = false;
|
||||
|
||||
std::unique_ptr<cli_user_t> user; // for http mode
|
||||
std::shared_ptr<user_info_t> user; // for http mode
|
||||
|
||||
ring_loop_t *ringloop = NULL;
|
||||
epoll_manager_t *epmgr = NULL;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
bool cli_tool_t::check_image_perm(const inode_config_t & cfg, bool write)
|
||||
{
|
||||
return !user ||
|
||||
user->type == "admin" ||
|
||||
user->type == user_type_t::ADMIN ||
|
||||
user->name == cfg.owner ||
|
||||
cfg.owner_group != "" && user->groups.find(cfg.owner_group) != user->groups.end() ||
|
||||
!write && cfg.reader_group != "" && user->groups.find(cfg.reader_group) != user->groups.end();
|
||||
|
||||
@@ -121,7 +121,7 @@ struct image_creator_t
|
||||
|
||||
bool check_pool_permission()
|
||||
{
|
||||
if (!parent->user || parent->user->type == "admin")
|
||||
if (!parent->user || parent->user->type == user_type_t::ADMIN)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ resume_1:
|
||||
inode_t inode_num = INODE_WITH_POOL(pool_id, only_inode_num);
|
||||
uint64_t used_size = kv.value["raw_used"].uint64_value();
|
||||
auto stat_it = stats.find(inode_num);
|
||||
if (parent->user && parent->user->type != "admin" && stat_it == stats.end())
|
||||
if (parent->user && parent->user->type != user_type_t::ADMIN && stat_it == stats.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
+33
-25
@@ -76,6 +76,7 @@ struct cli_serve_t
|
||||
int port = 0;
|
||||
int listen_backlog = 0;
|
||||
bool ssl = false;
|
||||
bool use_auth = false;
|
||||
std::vector<int> listen_fds;
|
||||
http_context_t *http_ctx = NULL;
|
||||
std::set<cli_serve_conn_t*> connections;
|
||||
@@ -111,19 +112,34 @@ struct cli_serve_t
|
||||
listen_backlog = options["listen_backlog"].uint64_value();
|
||||
if (!listen_backlog)
|
||||
listen_backlog = 128;
|
||||
ssl = json_is_true(options["ssl"]);
|
||||
if (ssl)
|
||||
{
|
||||
std::string ssl_cert = options["ssl_cert"].string_value();
|
||||
std::string ssl_key = options["ssl_key"].string_value();
|
||||
std::string ssl_ca = options["ssl_ca"].string_value();
|
||||
std::string error;
|
||||
http_ctx = http_context_init(parent->epmgr->tfd, ssl_cert, ssl_key, ssl_ca, ssl_ca != "", error);
|
||||
if (error != "")
|
||||
std::string tls_cert = (parent->cli->config.find("server_cert") != parent->cli->config.end()
|
||||
? parent->cli->config["server_cert"].string_value() : "");
|
||||
std::string tls_key = (parent->cli->config.find("server_key") != parent->cli->config.end()
|
||||
? parent->cli->config["server_key"].string_value() : "");
|
||||
std::string tls_ca = (parent->cli->config.find("client_ca") != parent->cli->config.end()
|
||||
? parent->cli->config["client_ca"].string_value() : "");
|
||||
if (tls_cert != "" || tls_key != "" || tls_ca != "")
|
||||
{
|
||||
result = (cli_result_t){ .err = EINVAL, .text = error };
|
||||
state = 100;
|
||||
return;
|
||||
ssl = true;
|
||||
if (tls_cert == "" || tls_key == "")
|
||||
{
|
||||
result = (cli_result_t){ .err = EINVAL, .text = "server_cert and server_key are required to serve HTTPS" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
// use_auth is enabled by default when client_ca is set
|
||||
use_auth = (parent->cli->config["use_auth"].is_null()
|
||||
? (tls_ca != "")
|
||||
: json_is_true(parent->cli->config["use_auth"]));
|
||||
std::string error;
|
||||
http_ctx = http_context_init(parent->epmgr->tfd, tls_cert, tls_key, tls_ca, tls_ca != "", error);
|
||||
if (error != "")
|
||||
{
|
||||
result = (cli_result_t){ .err = EINVAL, .text = error };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto & bind_address: bind_addresses)
|
||||
@@ -344,17 +360,9 @@ struct cli_serve_t
|
||||
conn->request_path = std::move(req_line[1]);
|
||||
conn->request_body = std::move(msg->body);
|
||||
conn->response_type = "";
|
||||
if (parent->cli->st_cli.use_auth)
|
||||
if (use_auth)
|
||||
{
|
||||
auto user = std::make_unique<cli_user_t>();
|
||||
user->name = msg->headers["_tls_common_name"];
|
||||
auto user_it = parent->cli->st_cli.user_info.find(user->name);
|
||||
auto userinfo = user_it == parent->cli->st_cli.user_info.end() ? user_it->second : json11::Json();
|
||||
user->type = user->name == "root" ? "admin" : userinfo["type"].string_value();
|
||||
for (auto & gr: userinfo["groups"].array_items())
|
||||
{
|
||||
user->groups.insert(gr.string_value());
|
||||
}
|
||||
conn->p->user = parent->cli->st_cli.get_user(msg->headers["_tls_common_name"]);
|
||||
}
|
||||
auto ctype = msg->headers["content-type"];
|
||||
if (conn->request_method != "GET" && conn->request_method != "POST")
|
||||
@@ -383,10 +391,10 @@ struct cli_serve_t
|
||||
{
|
||||
conn->response_type = "application/json";
|
||||
conn->result = { .text = openapi_description };
|
||||
if (parent->cli->st_cli.use_auth)
|
||||
if (use_auth)
|
||||
{
|
||||
// Filter available paths by privileges
|
||||
if (conn->p->user->type == "client")
|
||||
if (conn->p->user->type == user_type_t::CLIENT)
|
||||
{
|
||||
std::string error;
|
||||
auto openapi = json11::Json::parse(openapi_description, error).object_items();
|
||||
@@ -403,7 +411,7 @@ struct cli_serve_t
|
||||
conn->response_type = "application/json";
|
||||
conn->result = { .text = json11::Json(openapi).dump() };
|
||||
}
|
||||
else if (conn->p->user->type != "admin")
|
||||
else if (conn->p->user->type != user_type_t::ADMIN)
|
||||
{
|
||||
conn->response_type = "";
|
||||
conn->result = { .err = EACCES, .text = "Access denied" };
|
||||
@@ -418,7 +426,7 @@ struct cli_serve_t
|
||||
{
|
||||
conn->result = { .err = ENOSYS, .text = "method /"+uri[0]+" only allows POST requests" };
|
||||
}
|
||||
else if (parent->cli->st_cli.use_auth && conn->p->user->type == "client" && !cmd_it->second.allow_client)
|
||||
else if (use_auth && conn->p->user->type == user_type_t::CLIENT && !cmd_it->second.allow_client)
|
||||
{
|
||||
conn->result = { .err = EACCES, .text = "Access denied" };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user