PHP security seems to be stuck in the dark times of a single password, giving a single-user token for a class of specific pages. It seems you want to get much more features in your application, perhaps even allowing access to certain resources depending on this input token. Your idea of โโaccess control lists is absolutely correct, and yes, you have discovered a dark secret: no one has published how to create or write an ACL mechanism. However, this was done.
First off, are you familiar with unix file permissions ? " -rwxr-xr-x things that you see in ls -l on the command line. Unix took a very simplified approach to ACLs. Each registered user has a user identifier (UID) and one or more group identifiers (GIDs) ( whoami , groups ). Unix file permissions allow you to perform three operations: Read , Write and Execute , which can be turned on or off. With 2 ^^ 9 states, these permissions easily fit into an integer, and Unix can then attach this integer to the file directly in the file When a user tries to access a file , permissions are mapped to strict and permissive, which corresponds to allowed privileged privileges. Thus, users get the first set of permissions, groups get the second and everyone gets the third. Thus, the executable file is usually 755: only the owner can change it, but everyone can read and use it.
Secondly, LDAP is a lightweight directory access protocol that is designed to provide multiple network users access to resources. OpenLDAP is a common Linux implementation, and Microsoft Active Directory on Windows Server talks about LDAP (with many extensions). LDAP has a much more robust ACL system. General configuration access to [resources] by [who] [type of access granted] [control] or access to dn="uid=matt,ou=Users,dc=example,dc=com" by * none to restrict access to information user Matt. For a more complete discussion, I highly recommend LDAP Mastering , in particular chapter 4 on security. (This is where I understand my direct knowledge a little.) I get the impression that LDAP stores this information in a separate database table, but I donโt know this and cannot find the documentation anyway. I am following a possible scheme for this.
A brief stop to summarize: ACLs use the concept of a user token with possible groups above the user level, a collection of objects for protection in some way, and several consecutive possible operations on these parts - 3 dimensions of information. Unix stores two of these sizes with things that need to be provided directly. OpenLDAP stores these three dimensions separately, somehow we donโt quite know, but I suspect this is a related tree structure.
With that in mind, let's see how we could develop an ACL system for a RESTful web application. For assumptions, we decompose your application into discrete address units - every thing that needs to be protected will be available through a URI ( http://example.com/users , http://example.com/page_pieces/ticker ). Our users will be a simple UID / GIDs token - a user can be part of several groups. Finally, our available operations will be based on HTTP requests - GET, POST, PUT, DELETE, etc. Now we need a system that efficiently processes a 3-dimensional data array. Our scheme should be pretty obvious: (uri, userid, groupid, operations) . We intentionally denormalize the operations column to the list of rows GET,POST,... , so we only need one table. There is no primary key, since we will never search by ID.
Requests will be performed in two stages: SELECT * FROM acl WHERE uri=@uri , userid=@userid , which will return 0 or 1 lines. If it returns 1 line, we are done and we can grep permisssion to see if there is an operation in the list (use * to specify all perms). If we get 0 rows, run the second query SELECT * FROM acl WHERE uri=@uri , userid='*', groupid in (@groupid) , which will return 0 or more rows again. If it returns some of them, iterate over and look at perms. If it returns 0, make the last query SELECT * FROM acl WHERE uri=@uri , userid='*', groupid='*' , which will finally return 0 or 1 row. If it returns 1, look at perms. If it returns 0, follow the default action.
We can set permissions in several ways:
INSERT INTO acl VALUES (@uri, @userid, '', 'GET,POST') allows access to a single GET or POST userINSERT INTO acl VALUES (@uri, '*', 'admin,contributors', 'GET,PUT,POST,DELETE')INSERT INTO acl VALUES (@uri, '*', '*', '') denies access.
A few notes:
All URIs must be exactly expressed; this solution has no way to set the default permissions at a higher level and they will flow down (on the left as an exercise for the Questionnaire).
The uniqueness of uri / uid / gid pairs should happen at some point. An application can handle this, or in MySQL you can do ALTER TABLE acl ADD UNIQUE INDEX (uri, userid, groupid) (look for documentation for similar restrictions in other DBMSs).