I’m nearing the end of my development work for the first version of the NIST RBAC API for PHP. Rather than trying to explain this myself I quote the Wikipedia page on this and Role Based Access Control (RBAC) in general:
The NIST RBAC model is a standardized definition of role based access control. Although originally developed by the National Institute of Standards and Technology, the standard was adopted and is copyrighted and distributed as INCITS 359-2004 by the International Committee for Information Technology Standards (INCITS).
In computer systems security, role-based access control (RBAC)[1][2] is an approach to restricting system access to authorized users. It is a newer alternative approach to mandatory access control (MAC) and discretionary access control (DAC). RBAC is sometimes referred to as role-based security.
Within an organization, roles are created for various job functions. The permissions to perform certain operations are assigned to specific roles. Members of staff (or other system users) are assigned particular roles, and through those role assignments acquire the permissions to perform particular system functions. Unlike context-based access control (CBAC), RBAC does not look at the message context (such as a connection’s source).
Since users are not assigned permissions directly, but only acquire them through their role (or roles), management of individual user rights becomes a matter of simply assigning appropriate roles to the user; this simplifies common operations, such as adding a user, or changing a user’s department.
The NIST RBAC Model uses a limited set of concepts to define an RBAC system as depicted below. The system has (1) users, users have (2) sessions and sessions and users have (3) roles assigned to them. Each role consist of (4) permissions and permissions are based on (5) objects and (6) operations.
Great though standards are they hardly ever give you concrete stuff like an actual implementation or a data model. As part of my series of little releases leading up to the release of the NIST RBAC PHP API I’m delivering a worked out RBAC Data Model based on the NIST standard. The model has been designed with an ERD tool named “Dezign for Databases” and it can generate the DDL code for just about any database. For the moment I’m releasing this in MySQL 5 format but if there are requests for other databases please let me know and I’ll update the post accordingly.
An Entity-Relationship diagram of the model is depicted below:

The model contains 6 main entities:
- user: this contains all the user data
- session: this contains the session data for all currently logged on users
- role: this contains all the roles that are defined
- permissions: this contains all the permissions based on objects and operations
- object: objects are the items that require protection
- operation: operations are the actions that are performed on the objects
As you can see the entities in the data model map on the entities shown in the NIST RBAC entity model. Because there are a fair number of many-to-many relationships in the model there are a number of bridge tables to help out:
user_session: this combines the user with an active session, i.e. which users of the set of all users are currently logged inAs Alex pointed out in the comments below this is not a many-to-many relationship but a one-to-many relationship and therefore doens’t require a bridge table- user_role: this combines the user with any number of roles (but at least one)
- session_role: when a user logs in all the assigned roles are associated with the session. This allows for temporary changes to the role structure, i.e. take away a role for the duration of the session or add a role for the duration of the session
- role_permission: this associates a role with one or more permissions
The model is 4NF/5NF and fully relational. For MySQL usage it requires an InnoDB (or equivalent) database. I have only tested it myself with MySQL 5.0/5.1 and the InnoDB storage engine but there should be nothing in the DDL file that would conflict with other (transactional) storage engines. If you encounter problems with executing the file please let me know (don’t know if I can fix them but I’ll give it a try).
You can execute the code below as a SQL query, either directly in MySQL command line or via phpMyAdmin. Don’t forget to create a database, and select that database, before you execute the query!
# ---------------------------------------------------------------------- # # Script generated with: DeZign for Databases v6.1.2 # # Target DBMS: MySQL 5 # # Project file: rbac_nist_0_17.dez # # Project name: nist rbac model # # Author: m.e. post # # Script type: Database creation script # # Created on: 2010-07-31 20:26 # # ---------------------------------------------------------------------- # # ---------------------------------------------------------------------- # # Tables # # ---------------------------------------------------------------------- # # ---------------------------------------------------------------------- # # Add table "user" # # ---------------------------------------------------------------------- # CREATE TABLE `user` ( `user_id` INTEGER(8) NOT NULL AUTO_INCREMENT, `username` VARCHAR(40) NOT NULL, `password` VARCHAR(64) NOT NULL, `nonce` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00', `first_name` VARCHAR(50) NOT NULL, `family_name` VARCHAR(100) NOT NULL, `email` VARCHAR(100) NOT NULL, PRIMARY KEY (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; # ---------------------------------------------------------------------- # # Add table "role" # # ---------------------------------------------------------------------- # CREATE TABLE `role` ( `role_id` INTEGER(8) NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, PRIMARY KEY (`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; # ---------------------------------------------------------------------- # # Add table "user_role" # # ---------------------------------------------------------------------- # CREATE TABLE `user_role` ( `user_id` INTEGER(8) NOT NULL, `role_id` INTEGER(8) NOT NULL, PRIMARY KEY (`user_id`, `role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE INDEX `IDX_user_role_1` ON `user_role` (`user_id`); CREATE INDEX `IDX_user_role_2` ON `user_role` (`role_id`); # ---------------------------------------------------------------------- # # Add table "session" # # ---------------------------------------------------------------------- # CREATE TABLE `session` ( `session_id` INTEGER(8) NOT NULL AUTO_INCREMENT, `user_id` INTEGER(8) NOT NULL, `name` VARCHAR(64) NOT NULL, `created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`session_id`, `user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; # ---------------------------------------------------------------------- # # Add table "operation" # # ---------------------------------------------------------------------- # CREATE TABLE `operation` ( `operation_id` INTEGER(2) NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `_create` TINYINT(1) DEFAULT NULL, `_read` TINYINT(1) DEFAULT NULL, `_update` TINYINT(1) DEFAULT NULL, `_delete` TINYINT(1) DEFAULT NULL, `locked` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`operation_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; # ---------------------------------------------------------------------- # # Add table "object" # # ---------------------------------------------------------------------- # CREATE TABLE `object` ( `object_id` INTEGER(8) NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `locked` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`object_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; # ---------------------------------------------------------------------- # # Add table "permission" # # ---------------------------------------------------------------------- # CREATE TABLE `permission` ( `permission_id` INTEGER(8) NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `object_id` INTEGER(8) NOT NULL, `operation_id` INTEGER(2) NOT NULL, PRIMARY KEY (`permission_id`, `name`, `object_id`, `operation_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; CREATE INDEX `IDX_permission_1` ON `permission` (`object_id`); CREATE INDEX `IDX_permission_2` ON `permission` (`operation_id`); # ---------------------------------------------------------------------- # # Add table "role_permission" # # ---------------------------------------------------------------------- # CREATE TABLE `role_permission` ( `role_id` INTEGER(8) NOT NULL, `permission_id` INTEGER(8) NOT NULL, PRIMARY KEY (`role_id`, `permission_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE INDEX `IDX_role_permission_1` ON `role_permission` (`role_id`); CREATE INDEX `IDX_role_permission_2` ON `role_permission` (`permission_id`); # ---------------------------------------------------------------------- # # Add table "session_role" # # ---------------------------------------------------------------------- # CREATE TABLE `session_role` ( `role_id` INTEGER(8) NOT NULL, `session_id` INTEGER(8) NOT NULL, `user_id` INTEGER(8) NOT NULL, PRIMARY KEY (`role_id`, `session_id`, `user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE INDEX `IDX_session_role_1` ON `session_role` (`role_id`); CREATE INDEX `IDX_session_role_2` ON `session_role` (`session_id`); # ---------------------------------------------------------------------- # # Foreign key constraints # # ---------------------------------------------------------------------- # ALTER TABLE `user_role` ADD CONSTRAINT `user_user_role` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `user_role` ADD CONSTRAINT `role_user_role` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `session` ADD CONSTRAINT `user_session` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `permission` ADD CONSTRAINT `object_permission` FOREIGN KEY (`object_id`) REFERENCES `object` (`object_id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `permission` ADD CONSTRAINT `operation_permission` FOREIGN KEY (`operation_id`) REFERENCES `operation` (`operation_id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `role_permission` ADD CONSTRAINT `role_role_permission` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `role_permission` ADD CONSTRAINT `permission_role_permission` FOREIGN KEY (`permission_id`) REFERENCES `permission` (`permission_id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `session_role` ADD CONSTRAINT `role_session_role` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `session_role` ADD CONSTRAINT `session_session_role` FOREIGN KEY (`session_id`, `user_id`) REFERENCES `session` (`session_id`,`user_id`) ON DELETE CASCADE ON UPDATE CASCADE;
No related posts.

Alex said:
Hi,
if I’m not completely wrong you have a little mistake in your concept. You introduced a mapping table for sessions to users (or vice versa). This is not neccessary, since the ANSI/NIST standard does not specify a many-to-many relationship between users and sessions. Any session in RBAC belongs to exactly one user. So instead of mapping the user to a session in a separate table, you can reference the user directly in the session table. Which means one JOIN less needed.
Cheers
Alex
July 27, 2010 at 6:04 pm
postme said:
Hi Alex,
Thank you for your feedback, you had me worried a bit so I went back to check with the standard. This is what I found:
This excerpt is from page 7 of the “A Proposed Standard for Role-Based Access Control” document. After rereading this excerpt your argument certainly makes sense, there is no specific need for a many-to-many relationship but only a one-to-many relationship. I will change this in the database schema and associated code for the next version, probably will be in two weeks time.
Thanks for taking the time to let me know so I can improve the software.
Kind regards,
Meint
July 30, 2010 at 5:30 pm
Phil said:
Awsome explanation of RBAC. Would really like to see a working demo. Are you any close to releasing this stuff yet?
Eagerly awaiting…
Phil.
June 2, 2010 at 1:20 pm
postme said:
Hi Phil,
I’ve released the code and will post about it this evening, hope it’s to your liking (although one guy from the first test group rejected the code out of hand because it wasn’t OOP).
Meint
June 2, 2010 at 7:29 pm
Ashutosh Bijoor said:
Hi
Thanks for posting this. Looking forward to using your library. Can you give an update on the status of your development?
May 15, 2010 at 6:48 am
Tom said:
Have you release any code? I am very interested in contributing code. But I would like to see what you have done first.
Thanks in advance?
May 11, 2010 at 2:50 am
Milorad said:
Hey, really great stuff !
The correct implementation of RBAC, not too complicated, but yet, it has everything one needs to secure the system !
Could you only share with us default data, maybe ? It would be really great if you could !
Once again, great stuff !
Milorad
March 17, 2010 at 2:49 pm
Michael Plant said:
Thanks for taking the time to write this, it is really great!
I have never used the shortcut thing you are doing with operations? Can you point me in the right direction?
Do you have any default data for roles or permission? Have you implemented this and if so how is working for you?
I was looking to plan my ACL and starting reading about RBAC and found your site. Thanks again!
Mike Plant
January 30, 2010 at 4:01 am
postme said:
@Mike
Yes I have default data for roles and permissions, it’s part of the release I’m preparing that delivers the data model, library, management application, test framework and demo application. I’m trying to finish the documentation and release the package within two weeks.
Could you explain what you mean with “shortcut thing” that I applied with operations?
Meint
January 30, 2010 at 7:01 pm