Generic GRANT/REVOKE generation from ACL's complete.

Moved the owned concept to PgServerObject as it is needed for the generic
acl functionality that is also in PgServerObject.
This commit is contained in:
eelke 2018-12-25 13:17:04 +01:00
parent cc0b28e8e0
commit c2c01cf431
23 changed files with 358 additions and 312 deletions

190
pglablib/catalog/PgAcl.cpp Normal file
View file

@ -0,0 +1,190 @@
#include "PgAcl.h"
#include <QStringBuilder>
namespace {
QString privilegeLetterToKeyword(char c)
{
switch (c) {
case 'r': return "SELECT";
case 'w': return "UPDATE";
case 'a': return "INSERT";
case 'd': return "DELETE";
case 'D': return "TRUNCATE";
case 'x': return "REFERENCES";
case 't': return "TRIGGER";
case 'X': return "EXECUTE";
case 'U': return "USAGE";
case 'C': return "CREATE";
case 'c': return "CONNECT";
case 'T': return "TEMPORARY";
}
throw std::runtime_error("Unexpected value for c in privilegeLetterToKeyword");
}
}
char privilegeToChar(Privilege p)
{
switch (p) {
case Privilege::Select: return 'r';
case Privilege::Update: return 'w';
case Privilege::Insert: return 'a';
case Privilege::Delete: return 'd';
case Privilege::Truncate: return 'D';
case Privilege::References: return 'x';
case Privilege::Trigger: return 't';
case Privilege::Execute: return 'X';
case Privilege::Usage: return 'U';
case Privilege::Create: return 'C';
case Privilege::Connect: return 'c';
case Privilege::Temporary: return 'T';
}
throw std::runtime_error("Unexpected value for privilege in privilegeToChar");
}
PgAcl::PgAcl(const QString &acl)
{
setFromString(acl);
}
void PgAcl::setFromString(const QString &acl)
{
m_grantee = acl.section('=', 0, 0);
auto t = acl.section('=', 1);
m_privileges = t.section('/', 0, 0);
m_grantor = t.section('/', 1);
}
PrivValue PgAcl::privilege(Privilege priv) const
{
char c = privilegeToChar(priv);
return privilege(c);
}
PrivValue PgAcl::privilege(char c) const
{
int pos = m_privileges.indexOf(c);
if (pos >= 0) {
if ( (pos+1) < m_privileges.length() && m_privileges[pos+1] == '*')
return PrivValue::YesWithGrant;
return PrivValue::Yes;
}
return PrivValue::No;
}
QString PgAcl::singleString() const
{
return m_grantee % "=" % m_privileges % "/" % m_grantor;
}
//void operator<<(AclList &s, const Pgsql::Value &v)
void operator<<(PgAcl &acl, const Pgsql::Value &v)
{
acl.setFromString(v);
// const char *c = v.c_str();
// Pgsql::ArrayParser parser(c);
// while (true) {
// auto elem = parser.GetNextElem();
// if (!elem.ok)
// break;
// auto&& v = elem.value.value_or("");
// s.emplace_back(QString(v.data()));
// }
}
namespace Pgsql {
template <>
PgAcl StringToArrayElem<PgAcl>(std::string_view sv)
{
return PgAcl(QString::fromUtf8(sv.data(), static_cast<int>(sv.length())));
}
}
namespace {
void appendColumn(QString &rights, const QString &column)
{
if (!column.isEmpty()) {
rights += "(" % column % ")";
}
}
QString privilegeGrant(const QString &all_pattern, const QString &acl, const QString &grantOnObject, QString user, const QString &column)
{
QString rights;
if (user.isEmpty())
user = "PUBLIC";
if (all_pattern.length() > 1 && acl == all_pattern) {
rights = "ALL";
appendColumn(rights, column);
}
else {
for (auto c : acl) {
if (!rights.isEmpty())
rights += ", ";
rights += privilegeLetterToKeyword(c.toLatin1());
appendColumn(rights, column);
}
}
QString grant;
if (rights.isEmpty()) {
grant += "REVOKE ALL";
appendColumn(grant, column);
}
else
grant += "GRANT " + rights;
grant += " ON " + grantOnObject;
if (rights.isEmpty())
grant += " FROM ";
else
grant += " TO ";
grant += user;
return grant;
}
}
QString PgAcl::sql(const QString &all_pattern, const QString &grant_on_object, const QString &column) const
{
QString acl, acl_with_grant;
// Doorloop acl en scheid de rechten met GRANT optie van die zonder
for (auto c : all_pattern) {
switch(privilege(c.toLatin1())) {
case PrivValue::No:
break;
case PrivValue::Yes:
acl += c;
break;
case PrivValue::YesWithGrant:
acl_with_grant += c;
break;
}
}
QString sql;
// Call when acl is not empty or both are empty
// needs to be calledwhen both are empty to generate REVOKE
if (!acl.isEmpty() || acl_with_grant.isEmpty()) {
sql += privilegeGrant(all_pattern, acl, grant_on_object, m_grantee, column)
+ ";\n";
}
if (!acl_with_grant.isEmpty()) {
sql += privilegeGrant(all_pattern, acl_with_grant, grant_on_object, m_grantee, column)
+ " WITH GRANT OPTION;\n";
}
return sql;
}
bool PgAcl::empty() const
{
return m_privileges.isEmpty();
}