This question is inspired by this SO question regarding Access Control in ASP.NET MVC. Here I'm trying to bring the accepted answer into a tangible solution.
The answer mentions using FileSystemSecurity
as an inspiration to managing permissions. Here I'm also using an enum with Flags attribute to define the ACL for all my objects. Additionally each member of my objects will be stored in a column within SQL. Assume a simplified Linq2SQL, EF, or nHibernate ORM mapping.
Edit: Added the following benefit / rationale for this approach
This security model was inspired by the FileSystemRights, the .NET approach to managing file level permissions.
One of the main reasons I like this approach is so I can easily create a summary of all the permissions by OR'ing all the individual ACLs together. I also like that I can add a DENY ACL to remove an inherited permission.
List<myObject> PermissionsList = GetACLForObject(ItemID, UserID);
foreach (var acl in PermissionsList)
{
// The following enum has the [FlagsAttribute] applied so the .ToString() is pretty
PermissionWithFlagsEnum sampleForSO = (PermissionWithFlagsEnum )acl.Permission;
Console.Writeline ("Setting " + sampleForSO.ToString() + " permission for group: " + acl.ACLName);
ResultingPermission = resultPermission | acl.Permission ;
}
public int ResultingPermission {get;set;}
/End Edit
Then it occurred to me that I could compare less privileged users by numeric value of the enum
from more privileged users's enum
.
I'm thinking that this definition would allow for quick and easy identification of users within the SQL database, without having to parse the enum on the backend. ( Find unprivileged users via select users from permissions where security < DBAceessRights.DetailRead
)
Here is how I defined the flags (lowest value has the least permission)
[Flags]
public enum DBAccessRights
{
DenyAll =1 << 1,
WikiMode = 1 << 4,
AppearInListing = 1 << 8,
DetailRead = 1 << 12,
CreateNew = 1 << 18,
DetailEdit = 1 << 22,
DeleteChild = 1 << 26,
DeleteThis = 1 << 30,
EditPermissions = 1 << 31,
}
I have a permission table that joins a user ID to an object specific ACE. This should reduce the need for concurrent updates on a particular row.
Question
Is this a good idea?
Has someone done it before (better than this)? (Edit: It is the accepted answer here )
If this is a standard way of implementing permissions, what is it called?
In general putting multiple values (flags) into a single field is a bad idea.
If you're planning on auditing this data its a really bad idea since it because its hard to efficiently tease out which flags changed from update to update.
Problems you may encounter even if you don't do auditing
Many simple queries (what users the DeleteThis authroization) aren't SARGable because you'll need to perform a bitwise operation before a comparison.
Also
select users from permissions where security < DBAceessRights.DetailRead
may not return the right results becauseAppearInListing & CreateNew
is greater than DetailRead but doesn't have the DetailRead turned on. So the benefit you hoped for you may not getManaging concurrency (multiple writers to ACL) is more difficult since mutating one "logical value" is actually mutating all the values.