Thanks for elaborating, Weedpacket.
It's clear that having some incontrovertible "owner" with irrevocable privileges for every "object" is a scheme that has its benefits. I would point out a few things about this PostGreSQL that seem to be noteworthy and/or problematic if we hope to apply the same concept to a web application. I wish that I could provide some succinct mathematical expression of what, exactly, is problematic, but I can't quite put my finger on it. I suppose my goal in this thread is to try to understand what critical-but-minimal components are needed to build a permission system flexible enough to allow non-root users to edit permissions without introducing any security risk or functional roadblocks. It's hard to imagine all the possible circumstances one might encounter and very difficult to predict what risks might be involved.
First, there's this continuing reference to 'ownership' of 'objects' which, to me, either seems an inexact or incomplete or problematic notion to apply to the concept of privileges within a web application. I admit this may be due to my lack of logical imagination whereby I fail to recognize some mathematical equivalence between the concept of a data object and the concept of some action to be taken in a web application. I can certainly see that I already have some data object associated with permissions within my application -- i.e., the 'permission' table I defined before:
CREATE TABLE IF NOT EXISTS `permission` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`permission_name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
My experience says that my permission table works fine in the simple scenario of granting a user access to some simple resource. Some vaguely formed idea I have says that my permission scheme alone (which involves users, roles, user_role and role_permission etc.) is simply not up to the task if the permission in question involves the ability to view/edit/change/molest a data object that belongs to some other user -- or role to which they do not belong. E.g., some customer service rep must edit some user's data. I could easily add a user_id column to this permission table such that all permission objects were owned by some user/role and then I could hopefully assign my user-to-role-to-permission memberships/ownerships in such a way that my web application can expose an interface for editing permissions such that we don't have any unexpected/undesirable situations where some Janitor is revoking privileges from some VicePresident or whatever. I think in practice it gets very messy very quickly.
For anyone to edit someone else's data objects -- for which there is currently no role/group that grants edit permissions, it is necessary to introduce some privileged class of users who can control other people's data objects. This seems to be the case in PostGreSQL with the superusers you mentioned and also in MySQL with the root user. It might also be partly addressed by GRANT and REVOKE privileges on some database or table. The ability to delegate GRANT and REVOKE privileges on some object to other users presents its own problems. The existence of some uber-class of users (root, superuser, wheel, sudoers, whatever) is problematic for two reasons:
It introduces logical concepts entirely external to the data structures which defines permissions -- i.e., it's not about permissions for this privileged group. This 'superuser' idea requires extra logic and/or data somewhere to distinguish these special users, and this privileged status cannot be specified by and maintained with the tools that define your other permissions.
It is less flexible because it is basically a binary distinction. Either you are or you are not a member of this privileged class. This doesn't lend itself to hierarchical user relations (ceo vs. manager vs janitor). It's dangerous to bestow these privileges and limiting how many people can do this may introduce a lot of work for the small privileged crew.
If we have structures in our permission scheme that define an ability to GRANT or REVOKE privileges on some other data object, we have some other problems:
I suspect that the permission table I designed above will not be sufficient because we must somehow define special-case permissions which allow one to delegate other permissions (stored in the same permission table) to other people, etc. There appears to be some strange loop at work here (I called it Godelian before but that's just me bandying about concepts I know little about).
There seems to be an absence of 'hierarchy' in this scheme. GRANT/REVOKE privileges seem to be strictly about group membership and members of that group might abuse their privileges to attack other members as illustrated here:
Supposing we have some database, foo:
CREATE DATABASE foo;
We create two users, UserA and UserB, with all privileges on this table including GRANT:
CREATE USER 'UserA'@'localhost' IDENTIFIED BY '***';
GRANT USAGE ON * . * TO 'UserA'@'localhost' IDENTIFIED BY '***';
GRANT ALL PRIVILEGES ON `foo` . * TO 'UserA'@'localhost' WITH GRANT OPTION ;
CREATE USER 'UserB'@'localhost' IDENTIFIED BY '***';
GRANT USAGE ON * . * TO 'UserB'@'localhost' IDENTIFIED BY '***';
GRANT ALL PRIVILEGES ON `foo` . * TO 'UserB'@'localhost' WITH GRANT OPTION ;
then create some tables e.g., tbl1, tbl2, etc.
then UserA pulls a fast one on UserB
[codeREVOKE ALL PRIVILEGES ON foo . * FROM 'UserB'@'localhost';[/code]
UserA has effectively boxed UserB out. When UserB logs in, he can still see database foo, he can 'USE foo' and he can list the tables in foo:
USE foo;
SHOW TABLES;
But UserB cannot select any records from its tables:
SELECT * FROM tbl2;
ERROR 1142 (42000): SELECT command denied to user 'UserB'@'localhost' for table 'tbl2'
Nor can UserB restore his access to the table foo:
GRANT ALL PRIVILEGES ON `foo` . * TO 'UserB'@'localhost';
ERROR 1044 (42000): Access denied for user 'UserB'@'localhost' to database 'foo'
Perhaps PostGreSQL works differently, but the problem here is that the owner of the table (root in this case) can delegate GRANT/REVOKE privileges to a couple of lower-ranking users who are peers with each other, UserA and UserB, but these users and all users they might grant to are simply peers and can sabotage each other. This is kind of what I mean by 'no hierarchy.' Suppose UserA and UserB cannot edit each other's records but could possibly grant permissions to even lower-ranked users who could in turn delegate certain permissions to still lower ranked users?
I hope this doesn't sound like mumbo jumbo. Seems to me things get complicated very quickly and that the solutions we see now have very limited ability to delegate permissions and that delegation of permissions immediately introduces substantial risk or abuse.