I want to expose a REST service and use the permission context to call different methods (simple user vs admin user).
What I did (simple example):
config.add_route('rest', '/url')
....
#view_config(route_name="rest", renderer="json", request_method='GET', permission='user')
def firstMethod(request):
...
#view_config(route_name="rest", renderer="json", request_method='GET', permission='admin')
def secondMethod(request):
...
But I have the following error when I start pyramid :
"ConfigurationConflictError: Conflicting configuration actions"
for firstMethod and secondMethod
Any ideas to solve my problem ? (I know that I can use principals but I need to use permission and not principal...)
Your permissions right are labeled like principals, not permissions, so you might want to think about how you're actually using permissions. Principals are more like characteristics (groups), whereas permissions are like verbs (what can a user do).
As Martijn said, the way the ACL model works it's very difficult in a general sense to reason about whether one permission is mutually exclusive with another for arbitrary permissions. For example, are 'admin' users not 'user' users?? I guess that's up to you.
Pyramid provides a tiny way to cheat via the effective_principals predicate, if these are actually principals that you want to differentiate. Again you have to make sure they are mutually exclusive or you won't know which view will be invoked.
#view_config(route_name='foo', effective_principals=['admin'])
If admins also have the 'user' principal, then you'd leave 'user' out of the next view_config, as such:
#view_config(route_name='foo')
Now it's unambiguous.
The way to make this unambiguous in other cases is with your own view predicates.
#view_config(route_name='foo', is_admin=True)
#view_config(route_name='foo', effective_principals=[Authenticated])
config.add_view_predicate('is_admin', AdminPredicate)
Related
Edit: See my answer below.
For my needs, I decided to use both ACL and voters for my app (maybe it is not the best way, please, tell me if I'm wrong with this).
My entities represent a factory where there are :
Lines owning Workshops owning Equipments owning Spare Parts.
I want to give either a manager or a viewer access to a line level. For this purpose, I use an ACL on the line.
Because there are more than 5000 spare parts per line, I don't want to write 5000 ace to tell symfony that this user, which is allowed to manage this line, can manage the spare parts of the line.
To solve this problem, I decided to add a voter before the acl check.
I do a isGranted('edit',$sparepart) which is handled by a voter, and inside my own voter, I want to perform a isGranted('OPERATOR',$line).
Actually, I have many more things to check (is the user plant manager ? for example) and I like to combine the voter and the ACL.
Unfortunately, I'm a bit lost and I don't manage to call the right "isGranted" from my voter, I get an infinite loop error.
Voter isGranted
$authChecker = $this->get('security.authorization_checker');
$authChecker->isGranted('', $post);
ACL isGranted
$securityContext = $this->get('security.context');
$securityContext->isGranted('EDIT', $comment);
I understand this might be a bit confusing, and maybe I'm not doing it the right way :s
Thanks for your help !
So I finally did this in another way.
I use one voter and I created new entities to manage my access.
I have a LineAccess entity with:
ManyToOne: Line
ManyToOne: User
Sp_access: smallint
Cart_access: smallint
Line_access: smallint
So I check everything by myself and I also manage the links with my LineAccess entity and CustomerAccess entity.
Finally, it is the best way I think. Good luck
Here is the full problem for the curious :
For each user, I want to be able to select his permissions with this table.
If, for example, I check Boeing (the customer) manage. I will create an ACL/ACE with OPERATOR for this $customer.
That's it. Later, I want to check if this user is able to manage a line by first looking at a 'OPERATOR' on $line but if it doesn't exist, I will check 'OPERATOR' on $plant, and then 'OPERATOR' on $customer.
If I select Manage Dreamliner plant, I get this :
You can see that I'm still able to chose the kind of access to spare parts and cart. I can set this user, which is a plant manager, another permission : Spare parts manage. For that kind of permission, I can use the mask builder feature which allows me to store with a single integer "SP_MANAGER, CART_VALIDATE, LINE MANAGE', for example.
You can see that it gets a little complex here and this is why I think that ACL are my best friends, but I wanted to add a level of control in which I can manually select which isGranted() method, and on which entity.
I tried to be precise but it is not that easy :s
Thanks a lot for your help !
Voters and ACL are both standalone architecture approach to authorization. I'd recommend using Voters only, since they're easier to understand, use and extend.
For more details on this comparison, check these explanatory slides.
Where exactly you can't use Voters instead of ACL?
Also, why you need to nest Voters/ACL?
Thanks for your quick answer !
Actually, I thought I needed ACL because I have to put in the database my permissions. And here is the kind of permissions I want :
User A:
Manage line 1 (include workshops, equipments, sp) and can create shopping carts in this line.
View line 2 (can't manage the line but can see it's content) and can only validate the shopping carts.
So I thought it was good to use ACL because that way I can write in the database the permissions for each objects.
I also like the fact that I can use masks.
(There is the same logic on the Plant level)
I'm programming a new application with many users, a few roles and specific permissions for those roles. For that I want to create the following tables:
Users (ID,Login, password,..)
Roles(ID,Rolename)
User_Roles(User_ID, Role_ID)
Permissions(ID,PermissionName)
Permission_Roles(Permission_ID, Role_ID)
My idea was to build a function, which allows to check if a user has a specific permission to access a form. I would do that by creating Permissions/Rules like 'canReadFormX', 'canEditFormX' which would allow me to use one main function to check and perfom those specific rules and a function per form to call it.
Is that a way to go (or rather did I understand everything correctly regarding RBAC) or is that just far to complicated? Any advise is very appreciated!
It seems fair to me, and similar to what we have already set, for the first 3 tables.
You then have to solve the 'action' problem, ie to distribute permissions to use your appl's actions. I am not sure that your 'Permissions' proposal will cover all the situations, as you have to deal with 2 major categories of actions:
The 'Open form' actions, that you already have identified: you effectively have to define 2 levels of authorisation for each form: the 'view' right, and the 'update' right.
All other actions, such as form specific buttons or menus, that will allow you to run a specific action other than just opening a form (execute a report, make a specific calculation, automatically import or update data, etc).
One solution/My advice is to maintain 2 tables for this:
A 'Forms' table
An 'Actions' table
And the corresponding link tables:
A 'Form_Role' table
An 'Action_Role' table
With such a configuration, you are fully covered. You can even decide which role has the right to see a specific report on a specific form, as long as the corresponding action is accessed through a specific control or menu on the form.
Both Forms and Actions tables are very interesting as they both participate in your application metamodel...
EDIT: By the way, if you are on a domain, you can use user's domain credentials to control his\her access rights to your system. In this case you do not need to store a password in your RBAC system.
I have a discussion list and need to provide contribute access only to this list for all users with read access(i.e visitors). Basically, all visitors should be able to submit their comments in discussion list, but at same time no contribute access on any other lists of the child site. How can I do this without breaking the permissions inheritance from top level site??
Any workaround/ideas are appreciated..
"without breaking the permissions inheritance from top level site" <-- not possible!
Sharepoint's permission model is based on inheritance. If you want different permissions for one particular list, different from the rest of your site - you will need to break permission inheritance (hence the name inheritance).
Any reason why you don't want to break inheritance?
I've been struggling with this off and on for months, and it may be non-trivial to answer.
What is the easiest way to limit public access to an item and its subitems to members of a single role? (Editors still need to be able to edit the item.)
e.g. There's a role, extranet/clubmember, and items,
- Clubhouse
| - Items
| - Inside
| - Clubhouse
And I want extranet/clubmember members to be able to read the items and subitems, sitecore/* members (Or, say, sitecore/editor) to have edit access, and everyone else (in default and extranet domains) to be denied.
Second, does this solution still work with a custom role and membership providers for extranet? Why or why not, or what methods do I need to implement? I recall from earlier experiments that my custom role provider seems to affect Inheritance permissions in particular.
Have you tried the following:
uncheck Inherit for Everyone (the global one) to Clubhouse root
explicitly allow Read for extranet\clubmember to Clubhouse root
explicitly allow Read/Write for sitecore\Everyone to Clubhouse root
Explicit assignments always win. So, that scheme should have the effect you expect.
I'm searching for the best way to handle view-level authorization (where you hide markup based on a user's roles).
The typical way to do this is with the Acegi Security authz tag, as follows:
<authz:authorize ifAnyGranted="ROLE_FOO, ROLE_BAR, ROLE_BLAH">
<!-- protected content here -->
</authz:authorize>
The problem with that approach is that it quickly gets messy. For one, you either hard code the user roles as above or you create a constants file that duplicates them all. Second, there's no way with the current scheme to group roles logically. I suppose one solution is to define a separate role for each UI element, but then the declarative method level security on the business methods would need to be updated for each UI element (would that be a good thing?). This would also cause a proliferation of user roles! The use cases for my application actually mandate very few, e.g., Manager, Manager Supervisor, Super User (can do everything), Read Only, etc.
The solution that comes to mind is to treat the authorizable UI elements similar to message resources. That is, define a series of "authorization points" in a properties file similar to a MessageResources file. My initial thoughts are as follows:
com.lingoswap.home.editUserNameButton.ifAnyGranted=ROLE_FOO, ROLE_BAR, ROLE_BLAH
com.lingoswap.home.deleteAccountButton.ifNotGranted=ROLE_NOOB
com.lingoswap.home.deleteAccountButton.ifAnyGranted=ROLE_ADMIN
...
To protect content on the home page, we would then use a different protected tag (one that borrowed heavily from the original authz, possibly a sub class):
<security:protect component="com.lingoswap.home.editUserNameButton">
<!-- edit user name button -->
</security:protect>
<security:protect component="com.lingoswap.deleteAccountButton">
<!-- show the awesome delete account button that's not for nincompoops -->
</security:protect>
The advantages to this approach are the following:
Easy to test - we can write unit tests that verify the user-role-to-ui-element mappings (of course, it still has to be used on JSPs)
Error checking at runtime (and test time) - if a user role is misspelled in the .properties file, we can throw an Exception
Easy to tweak user roles - the requirements team continually refines the user roles; it'd be nice to change them all in one central location
Easy to understand - we can at a glance view the user role permissions for the entire application
Can be done DRYly (using property Spring placeholders to group related roles, e.g., ${readOnlyGroup} can be used in the properties file instead of the actual role names
The disadvantages seem to be:
Moderate complexity
Others??
Thanks for your advice.
Regards,
LES2
I did somethig similar to the second approach. And because I wanted all my security definitions in one place I implemented my own objectDefinitionSource for the FilterSecurityInterceptor.