I am creating a permissions system for a large application. This application will have a very broad scope, and is
very componentized. Which means that each component may have it's own set of permissions that it will need to
add to the system.
I have come up with what I believe are the two best solutions:
- Permission Bitmask
- Named Permissions
(Of course I am open to other solutions)
Let me elaborate...
Example of permissions bitmask:
...
use constant READ_PERM => 0x04;
use constant WRITE_PERM => 0x02;
use constant EXECUTE_PERM => 0x01;
use constant NO_PERM => 0x00;
my $allowed_perms = READ_PERM | WRITE_PERM;
# Check for permissions:
if ( $allowd_perms == NO_PERM )
{
print "PERMISSION DENIED\n"
exit -1;
}
if ( $allowed_perms & READ_PERM )
print "READ Allowed\n";
if ( $allowed_perms & WRITE_PERM )
print "WRITE Allowed";
if ( $allowed_perms & EXECUTE_PERM )
print "EXECUTE Allowd\n";
...
This method requires that we have 1 bit for every permission across the entire system. Thus a system with 256 distinct permissions will represent the integer 1.15792089237316e+77. To assign a user a permissinos mask we bitwise OR the permissions bits together. To check for a particular permission in the mask we bitwise AND the permission bit that we are looking for against the user's mask.
The pros:
- is very easy to use
- cheap to pass permissions around the in the system
The cons:
- size : A mysql BIGINT would only allow 64 unique permissions (there is a nasty workaround for this limitation involving stringification (yuck!))
- maintainability : MUCH care would need to be taken when adding new permissions to the system
The next approach is named permissions. This method implements permissions as a list of text tokens.
For example:
use constant READ_PERM => READ_PERM
use constant WRITE_PERM => WRITE_PERM;
use constant EXECUTE_PERM => EXECUTE_PERM;
my @allowed_perms = (
READ_PERM,
EXECUTE_PERM
);
# Check permissions
if ( scalar(@allowed_perms) == 0 )
{
print "PERMISSION DENIED\n";
exit -1;
}
if ( grep { $_ == READ_PERM } @allowed_perms )
print "READ Allowed\n";
if ( grep { $_ == WRITE_PERM } @allowed_perms )
print "WRITE Allowed\n";
if ( grep { $_ == EXECUTE_PERM } @allowed_perms )
print "EXECUTE Allowed\n";
The pros:
- Flexibility : This approach lends itself to namespacing and partitioning much easier than the bitmask method.
- Maintainability : Permissions aren't necessarily required to be defined in one location (given namespacing is in use)
- Allows components to add new permissions to the system without requiring a central registry or human intervention.
The cons:
- SIZE : A list of text tokens is much larger than a single integer.
- more difficult to use : in the since that we would probably use grep (or we could use exists if we put the permissions in a hash) either way we are using a function call as opposed to a simple logic operator
The question is which one is better in the opinion of this community and/or are there better ways of doing this than the two that I have laid out?
The objectives are to create an access control system that is flexible, maintainable, and easy to use.
Many of you would point out that by those virtues the named permission method would fit the bill more closely. Too true. However, I am hoping that some of you see something I've missed. I personally prefer the bitmask method, however the problem of having a large enough place to store the mask without stringifying it is a problem.
Any constructive criticism, comments and/or suggestions are greatly welcomed and desired.
Thank you all for your hard work and attention.
update (broquaint): fixed missing </ul> tag
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.