PgServerObject now contains a list of acl's for the object so all the different objects

can use this implementation.
This commit is contained in:
eelke 2018-12-24 07:51:27 +01:00
parent efb3e71556
commit 93c8b49f61
6 changed files with 284 additions and 36 deletions

View file

@ -87,7 +87,7 @@ QVariant ProcTableModel::getData(const QModelIndex &index) const
if (lan) return lan->objectName();
return t.lang;
}
case AclCol: return t.acl;
case AclCol: return t.aclString();
}
return QVariant();
}

View file

@ -410,24 +410,3 @@ QString getConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstr
return result;
}
//rolename=xxxx -- privileges granted to a role
// =xxxx -- privileges granted to PUBLIC
// r -- SELECT ("read")
// w -- UPDATE ("write")
// a -- INSERT ("append")
// d -- DELETE
// D -- TRUNCATE
// x -- REFERENCES
// t -- TRIGGER
// X -- EXECUTE
// U -- USAGE
// C -- CREATE
// c -- CONNECT
// T -- TEMPORARY
// arwdDxt -- ALL PRIVILEGES (for tables, varies for other objects)
// * -- grant option for preceding privilege
// /yyyy -- role that granted this privilege

View file

@ -56,17 +56,11 @@ class PgProc: public PgNamespaceObject, public PgOwnedObject {
public:
using PgNamespaceObject::PgNamespaceObject;
// Oid oid = InvalidOid; // oid
// QString name; // name
// Oid pronamespace = InvalidOid; // oid, namespace
// Oid owner = InvalidOid; // oid
Oid lang = InvalidOid; // oid
float cost = 0.f; // float4
float rows = 0.f; // float4
Oid variadic = InvalidOid; // oid
QString transform; // regproc
// bool isagg = false; // bool < 11
// bool iswindow = false; // bool << 11
ProcKind kind = ProcKind::Function; // >= 11
bool secdef = false; // bool
bool leakproof = false; // bool
@ -81,7 +75,6 @@ public:
QString src; // text
QString bin; // text
std::vector<QString> config; // text[]
QString acl; // aclitem[]
/// Converts the collection of arrays about the arguments to a single list of arguments
/// making it much easier to work with them correctly
@ -94,11 +87,6 @@ public:
);
const std::vector<Arg>& args() const;
// bool operator==(Oid _oid) const { return oid == _oid; }
// bool operator==(const QString &n) const { return name == n; }
// bool operator<(Oid _oid) const { return oid < _oid; }
// bool operator<(const PgProc &rhs) const { return oid < rhs.oid; }
const QString& createSql() const;
QString argListWithNames(bool multiline = false) const;
QString argSigList(const bool forScript = false) const;

View file

@ -49,8 +49,10 @@ PgProc PgProcContainer::loadElem(const Pgsql::Row &row)
std::optional<QString> argdefaults; // pg_node_tree
col.getAsVector<Oid>(std::back_inserter(argtypes));
col >> allargtypes >> argmodes >> argnames >> argdefaults
>> v.src >> v.bin >> v.config >> v.acl;
>> v.src >> v.bin >> v.config; // >> v.acl;
AclList acl_list;
col >> acl_list;
v.setAcls(std::move(acl_list));
v.setArgs(argtypes, allargtypes, argmodes, argnames, argdefaults);
if (minimumVersion(90500)) {

View file

@ -1,2 +1,211 @@
#include "PgServerObject.h"
#include "ArrayParser.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())));
}
}
void PgServerObject::setAcls(AclList acls)
{
m_acls = std::move(acls);
}
QString PgServerObject::aclString() const
{
QString result;
for (auto&& acl : m_acls) {
if (result.isEmpty()) result += "{";
else result += ",";
result += acl.singleString();
}
if (!result.isEmpty())
result += "}";
return result;
}
QString PgServerObject::grantSql(const QString &all_pattern, const QString &grantee, const QString &column) const
{
QString grant;
// wxString grant, str, user, grantFor, tmpUser;
// if (_grantFor.IsNull())
// {
// grantFor = GetTypeName();
// grantFor.MakeUpper();
// grantFor += wxT(" ") + GetQuotedFullIdentifier();
// }
// else
// grantFor = _grantFor;
// if (!acl.IsNull())
// {
// if (acl == wxT("{}"))
// {
// grant += GetPrivileges(allPattern, str, grantFor, wxT("public"), qtIdent(_column));
// grant += GetPrivileges(allPattern, str, grantFor, qtIdent(owner), qtIdent(_column));
// }
// else
// {
// // checks if certain privilege is granted to public
// bool grantedToPublic = false;
// // checks if certain privilege is granted to owner
// bool grantedToOwner = false;
// queryTokenizer acls(acl.Mid(1, acl.Length() - 2), ',');
// while (acls.HasMoreTokens())
// {
// str = acls.GetNextToken();
// if (str.Left(1) == '"')
// str = str.Mid(1, str.Length() - 2);
// user = str.BeforeFirst('=');
// str = str.AfterFirst('=').BeforeFirst('/');
// if (user == wxT(""))
// {
// user = wxT("public");
// grantedToPublic = true;
// }
// else
// {
// if (user.Left(6) == wxT("group "))
// {
// tmpUser = user.Mid(6);
// if (user.Mid(6).StartsWith(wxT("\\\"")) && user.Mid(6).EndsWith(wxT("\\\"")))
// user = wxT("GROUP ") + qtIdent(user.Mid(8, user.Length() - 10));
// else
// user = wxT("GROUP ") + qtIdent(user.Mid(6));
// }
// else
// {
// tmpUser = user;
// if (user.StartsWith(wxT("\\\"")) && user.EndsWith(wxT("\\\"")))
// user = qtIdent(user.Mid(2, user.Length() - 4));
// else
// user = qtIdent(user);
// }
// if (tmpUser.Contains(owner))
// grantedToOwner = true;
// }
// grant += GetPrivileges(allPattern, str, grantFor, user, qtIdent(_column));
// }
// str = wxEmptyString;
// int metaType = GetMetaType();
// // We check here that whether the user has revoked prvileges granted to databases, functions
// // and languages. If so then this must be part of reverse engineered sql statement
// if (!grantedToPublic && (metaType == PGM_LANGUAGE || metaType == PGM_FUNCTION || metaType == PGM_DATABASE))
// grant += GetPrivileges(allPattern, str, grantFor, wxT("public"), qtIdent(_column));
// // We check here that whether the owner has revoked prvileges on himself to this postgres
// // object. If so then this must be part of reverse engineered sql statement
// if (!grantedToOwner)
// grant += GetPrivileges(allPattern, str, grantFor, qtIdent(owner), qtIdent(_column));
// }
// }
return grant;
}

View file

@ -3,13 +3,83 @@
#include <QString>
#include "PgObject.h"
#include "Pgsql_Value.h"
#include <vector>
enum class Privilege {
Select,
Update,
Insert,
Delete,
Truncate,
References,
Trigger,
Execute,
Usage,
Create,
Connect,
Temporary
};
char privilegeToChar(Privilege p);
enum class PrivValue {
No, Yes, YesWithGrant
};
class PgAcl {
public:
PgAcl() = default;
explicit PgAcl(const QString &acl);
void setFromString(const QString &acl);
PrivValue privilege(Privilege priv) const;
PrivValue privilege(char c) const;
const QString& grantee() const { return m_grantee; }
const QString& grantor() const { return m_grantor; }
QString singleString() const;
private:
QString m_grantee;
QString m_grantor;
QString m_privileges;
};
using AclList = std::vector<PgAcl>;
void operator<<(PgAcl &acl, const Pgsql::Value &v);
namespace Pgsql {
template <>
PgAcl StringToArrayElem<PgAcl>(std::string_view sv);
}
/// Base object for objects that belong to a server
class PgServerObject: public PgObject {
public:
using PgObject::PgObject;
/**
* @brief setAcls Takes the acl array as stored by postgres as a single string
* and decodes it directly into an AclList.
* @param acls
*
*/
void setAcls(AclList acls);
QString aclString() const;
/**
* @brief grantSql
* @param all_pattern Used to recognize when a GRANT ALL can be generated but also to not consider irrelevant letters.
* @param grantee
* @param column
* @return
*/
QString grantSql(const QString &all_pattern, const QString &grantee, const QString &column) const;
private:
AclList m_acls;
};
#endif // PGSERVEROBJECT_H