I am following this cake php acl model article to create my own acl implementation.
I have understood the concepts of ACO ARO and ACO_ARO. I want to implement the Check method which will decide whether the aro has access to the aco. since there are ARO trees and ACO trees, how do i calculate the most effective permissions for a aco to a aro.
Also i have found the below article which has check method implemented but that is in php
acl implementation
In short, what should take precedence Account or group, aco or parent aco.
something like this article
update
uptill now i have reached till here
i have made a accessControlEntry class as follows
public class AccessControlEntry
{
public BsonObjectId AccessControlEntryId { get; set; }
public BsonObjectId AccessRequestObjectId { get; set; }
public BsonObjectId AccessControlObjectId { get; set; }
public bool CanView { get; set; }
public bool CanEdit { get; set; }
public bool CanDelete { get; set; }
public bool CanAdministrate { get; set; }
}
public bool Check(Usercontext usercontext, BsonObjectId acoId, string permission)
{
//aco id is accessControlObjectId like in cakephp acl
Account acc = _usercontextService.GetAccountByUserContext(usercontext);
//getting ACE eg X account has CanRead=true on Y object
AccessControlEntry entry = _accessControlEntryRepository.GetAccessControlEntry(acc.AccountId, acoId);
if (entry != null)
{
bool value = (bool)entry.GetType().GetProperty(permission).GetValue(entry, null);
return value;
}
//account entry not found ...search in groups
bool groupEntryFound = false;
bool effectiveValue = false;
Group[] groups = _usercontextService.GetGroupsForAccount(acc.AccountId);
foreach (Group group in groups)
{
AccessControlEntry entryGroup = _accessControlEntryRepository.GetAccessControlEntry(group.GroupId, acoId);
if (entryGroup != null)
{
groupEntryFound = true;
effectiveValue |= (bool)entryGroup.GetType().GetProperty(permission).GetValue(entryGroup, null);
}
}
//ACE found in group ..return most privilged value
if (groupEntryFound)
return effectiveValue;
//entry not found for account nor for group..return false
return false;
}
I call the check method from other services ike this
Check(context,44556,"CanRead")
The check method looks for AccessControlEntry for the account, if it does not find any entry for account then it looks for groups.
Given the above information we can write some simple tooling, in my case I am working with a content management system so my ACL’s are about page access.
First I define what my ACL entries look like …
Then I create a helper class to handle the evaluations …
This now gives me all the control I simply pass that a page and an IPrincipal object and I get back an ACLEntry that represents the level of access.
I decided to further abstract away my security implementation by making the Calculation method private and only the CanX methods public.
So now it’s as simple as
It seems like theres a lot of code but if you take out the formatting and comments (to meet coding standards) there’s actually very little code, and if you copy this in in to a class file in Visual Studio it’s actually very easy to follow and maintain.
You may also note, not once do I pass in a repository or service class to get data, that’s because I use this to build objects that are written using code first EF modelling an i’m using lazy loading, so your implementation might require a bit more than page.parent.AClEntries to go crawling up the tree.
Oh just in case you need it here’s my page class …
Very simple poco … using the power of EF to do all my on demand SQL crawling.
The one down side … i doubt it’s particularly efficient if you have a page deeply nested in a tree.
I’m still open to suggestions on improving this but this felt like the cleanest way to implement a managable solution at the time.
Now i have total visibility of the problem I can look to make those efficiency gains.
But at least you have a point of reference right 🙂