More correct implementation

This commit is contained in:
alesapin 2021-05-22 19:07:47 +03:00
parent 6e593cda7b
commit b9e9c9cf23
4 changed files with 140 additions and 37 deletions

View File

@ -142,6 +142,8 @@ void GetRequest::addRootPath(const String & root_path) { Coordination::addRootPa
void SetRequest::addRootPath(const String & root_path) { Coordination::addRootPath(path, root_path); }
void ListRequest::addRootPath(const String & root_path) { Coordination::addRootPath(path, root_path); }
void CheckRequest::addRootPath(const String & root_path) { Coordination::addRootPath(path, root_path); }
void SetACLRequest::addRootPath(const String & root_path) { Coordination::addRootPath(path, root_path); }
void GetACLRequest::addRootPath(const String & root_path) { Coordination::addRootPath(path, root_path); }
void MultiRequest::addRootPath(const String & root_path)
{

View File

@ -148,6 +148,40 @@ struct WatchResponse : virtual Response
using WatchCallback = std::function<void(const WatchResponse &)>;
struct SetACLRequest : virtual Request
{
String path;
ACLs acls;
int32_t version = -1;
void addRootPath(const String & root_path) override;
String getPath() const override { return path; }
size_t bytesSize() const override { return path.size() + sizeof(version) + acls.size() * sizeof(ACL); }
};
struct SetACLResponse : virtual Response
{
Stat stat;
size_t bytesSize() const override { return sizeof(Stat); }
};
struct GetACLRequest : virtual Request
{
String path;
void addRootPath(const String & root_path) override;
String getPath() const override { return path; }
size_t bytesSize() const override { return path.size(); }
};
struct GetACLResponse : virtual Response
{
ACLs acl;
Stat stat;
size_t bytesSize() const override { return sizeof(Stat) + acl.size() * sizeof(ACL); }
};
struct CreateRequest : virtual Request
{
String path;

View File

@ -8,6 +8,8 @@
#include <sstream>
#include <iomanip>
#include <Poco/SHA1Engine.h>
#include <Poco/Base64Encoder.h>
#include <boost/algorithm/string.hpp>
namespace DB
{
@ -32,6 +34,17 @@ static std::string getBaseName(const String & path)
return std::string{&path[basename_start + 1], path.length() - basename_start - 1};
}
static String base64Encode(const String & decoded)
{
std::ostringstream ostr; // STYLE_CHECK_ALLOW_STD_STRING_STREAM
ostr.exceptions(std::ios::failbit);
Poco::Base64Encoder encoder(ostr);
encoder.rdbuf()->setLineLength(0);
encoder << decoded;
encoder.close();
return ostr.str();
}
static String getSHA1(const String & userdata)
{
Poco::SHA1Engine engine;
@ -40,18 +53,32 @@ static String getSHA1(const String & userdata)
return String{digest_id.begin(), digest_id.end()};
}
static bool checkACL(int32_t permission, const Coordination::ACLs & node_acls, const std::vector<String> & session_auths)
static String generateDigest(const String & userdata)
{
std::vector<String> user_password;
boost::split(user_password, userdata, [](char c) { return c == ':'; });
return user_password[0] + base64Encode(getSHA1(user_password[1]));
}
static bool checkACL(int32_t permission, const Coordination::ACLs & node_acls, const std::vector<KeeperStorage::AuthID> & session_auths)
{
if (node_acls.empty())
return true;
for (size_t i = 0; i < node_acls.size(); ++i)
{
if (!(node_acls[i].permissions & permission))
for (const auto & session_auth : session_auths)
if (session_auth.scheme == "super")
return true;
if (node_acls[i].id == session_auths[i])
return true;
for (size_t i = 0; i < node_acls.size(); ++i)
{
if (node_acls[i].permissions & permission)
{
if (node_acls[i].scheme == "world" && node_acls[i].id == "anyone")
return true;
if (node_acls[i].scheme == session_auths[i].scheme && node_acls[i].id == session_auths[i].id)
return true;
}
}
return false;
@ -93,6 +120,34 @@ static KeeperStorage::ResponsesForSessions processWatchesImpl(const String & pat
return result;
}
static bool fixupACL(
const std::vector<Coordination::ACL> & request_acls,
const std::vector<KeeperStorage::AuthID> & current_ids,
std::vector<Coordination::ACL> & result_acls)
{
if (request_acls.empty())
return false;
for (const auto & request_acl : request_acls)
{
if (request_acl.scheme == "world" && request_acl.id == "anyone")
{
result_acls.push_back(request_acl);
}
else if (request_acl.scheme == "auth")
{
for (const auto & current_id : current_ids)
{
Coordination::ACL new_acl = request_acl;
new_acl.scheme = current_id.scheme;
new_acl.id = current_id.id;
result_acls.push_back(new_acl);
}
}
}
return !result_acls.empty();
}
KeeperStorage::KeeperStorage(int64_t tick_time_ms)
: session_expiry_queue(tick_time_ms)
{
@ -193,31 +248,15 @@ struct KeeperStorageCreateRequest final : public KeeperStorageRequest
else
{
auto & session_auth_ids = storage.session_and_auth[session_id];
for (size_t i = 0; i < request.acls.size(); ++i)
{
if (request.acls[i].id.empty())
{
if (!session_auth_ids[i].empty())
request.acls[i].id = session_auth_ids[i];
}
else
{
auto request_sha = getSHA1(request.acls[i].id);
if (session_auth_ids[i] != request_sha) /// User specified strange user:password in request
{
/// User specified strange user:password in request
response.error = Coordination::Error::ZAUTHFAILED;
return { response_ptr, {} };
}
else
{
request.acls[i].id = request_sha;
break;
}
}
}
KeeperStorage::Node created_node;
if (!fixupACL(request.acls, session_auth_ids, created_node.acls))
{
response.error = Coordination::Error::ZINVALIDACL;
return {response_ptr, {}};
}
created_node.stat.czxid = zxid;
created_node.stat.mzxid = zxid;
created_node.stat.ctime = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
@ -227,7 +266,6 @@ struct KeeperStorageCreateRequest final : public KeeperStorageRequest
created_node.stat.ephemeralOwner = request.is_ephemeral ? session_id : 0;
created_node.data = request.data;
created_node.is_sequental = request.is_sequential;
created_node.acls = request.acls;
std::string path_created = request.path;
@ -722,18 +760,35 @@ struct KeeperStorageAuthRequest final : public KeeperStorageRequest
Coordination::ZooKeeperAuthRequest & auth_request = dynamic_cast<Coordination::ZooKeeperAuthRequest &>(*zk_request);
Coordination::ZooKeeperResponsePtr response_ptr = zk_request->makeResponse();
Coordination::ZooKeeperAuthResponse & auth_response = dynamic_cast<Coordination::ZooKeeperAuthResponse &>(*response_ptr);
auto & sessions_and_auth = storage.session_and_auth;
if (auth_request.scheme != "digest")
if (auth_request.scheme == "super")
{
if (generateDigest(auth_request.data) == storage.superdigest)
{
KeeperStorage::AuthID auth{"super", ""};
sessions_and_auth[session_id].emplace_back(auth);
}
else
{
auth_response.error = Coordination::Error::ZAUTHFAILED;
}
}
else if (auth_request.scheme == "world" && auth_request.data == "anyone")
{
KeeperStorage::AuthID auth{"world", "anyone"};
sessions_and_auth[session_id].emplace_back(auth);
}
else if (auth_request.scheme != "digest")
{
auth_response.error = Coordination::Error::ZAUTHFAILED;
}
else
{
auto & sessions_and_auth = storage.session_and_auth;
std::string id = getSHA1(auth_request.data);
KeeperStorage::AuthID auth{auth_request.scheme, generateDigest(auth_request.data)};
auto & session_ids = sessions_and_auth[session_id];
if (std::find(session_ids.begin(), session_ids.end(), id) == session_ids.end())
sessions_and_auth[session_id].emplace_back(id);
if (std::find(session_ids.begin(), session_ids.end(), auth) == session_ids.end())
sessions_and_auth[session_id].emplace_back(auth);
}
return { response_ptr, {} };

View File

@ -51,6 +51,17 @@ public:
Coordination::ZooKeeperRequestPtr request;
};
struct AuthID
{
std::string scheme;
std::string id;
bool operator==(const AuthID & other) const
{
return scheme == other.scheme && id == other.id;
}
};
using RequestsForSessions = std::vector<RequestForSession>;
using Container = SnapshotableHashTable<Node>;
@ -59,13 +70,12 @@ public:
using SessionIDs = std::vector<int64_t>;
/// Just vector of SHA1 from user:password
using AuthIDs = std::vector<std::string>;
using AuthIDs = std::vector<AuthID>;
using SessionAndAuth = std::unordered_map<int64_t, AuthIDs>;
SessionAndAuth session_and_auth;
using Watches = std::map<String /* path, relative of root_path */, SessionIDs>;
Container container;
Ephemerals ephemerals;
SessionAndWatcher sessions_and_watchers;
@ -85,6 +95,8 @@ public:
return zxid;
}
const String superdigest;
public:
KeeperStorage(int64_t tick_time_ms);