I have a CMS system where admin can create user groups and can grant permissions to groups to do certain things. The permissions (CRUD) are granted on the objects (i.e: can add post, can edit own post, can delete someone else's post, ...)
It's easy to come to the conclusion that we should use something like the provided ACL and store permissions on object or class. However, the question is where should we put these security checking code?
One thing came to my mind was to put that in the controller, but now it means I have to edit every controller I have, or even if I don't I need to somehow identify the object/class that the specific controller action is trying to modify. Sometimes, the controller action will involve several objects/models at once and that makes things even more complicated.
I could also put that in the manager, so that whenever I invoke the save() method I can check for permission. For some reason, that approach seems wrong in term of performance and complexity.
I have read many posts explaining voters, acl and such for Symfony and I understand all that but I'm having trouble putting all that into a solution that would avoid dirty hacks such as editing every single controller.
Related
...without actually saving data to that node?
For example, I have a chat app. I'd like to check whether a user has write access to a node before showing the "Send message" button.
Define another node with the exact same set of security rules, that exists for no reason other than to perform these checks, and attempt a write there first to see if it finishes without error.
The most common approach is to replicate a similar, simplified version of the rules in your application code. You'd typically only replicate the benign checks, and leave extra validations against malicious users solely on the server.
Although I must admit Doug's version also sounds interesting. :-)
I am using Symfony ( current version 2.6.4 ) whenever I want to check if a user is loggedin ( I am also using FOSUserBundle ) I use $user = $this->getUser(); in my controller which works out just fine but if I open 10 links in 1 second this query is repeated for all 10 pages in that second, not so ideal in my option. So my question is, is there a way to cache this query for say 60 seconds and is it even advisable, will it affect new registrations or something. I am using APC as my doctrine cache but if someone knows the answer please also tell us how to use other ways incase other people also wonder how to do this. Thanks.
To start with, sql databases do a good job of automatically caching queries. So while there is some overhead in composing and sending the query to the server, the server itself will respond very quickly. You won't save much be adding another cache.
Should you still try and optimize? In your example of 10 requests per second one assumes that the requests are actually doing something besides getting the user. It's up to you to decide if caching the query will actually speed things up. In most cases the answer will be no. Trying to save every possible microsecond is called premature optimization and is something to avoid.
Having said that, it's worthwhile to look at what the security system is doing. Selected user information is stored in the session. You can use the debug profile bar to look at it. For each request, the security system pulls the user out of the session and then calls $user = $userProvider->refreshUser($user); By default, refreshUser is what causes the database to be queried.
You can easily plug in your own user provider (http://symfony.com/doc/current/cookbook/security/custom_provider.html) which just returns $user. No database interaction at all. Of course if the user's database information does change then they will need to log out and then log back in to see the changes. Or do something else to trigger a real refresh. But for many apps, not refreshing at all will work just fine.
It would also be easy enough to put a time stamp into the session. Your refreshUser method could then use the time stamp to decide if a refresh was actually needed.
So it's easy enough to eliminate the query and actually worthwhile just as a learning experience. Security is one of the more complicated components. The more you understand it the better off you will be. Customizing a user provider is one of the easier things to do.
I just saw your comment about the OAuthBundle. I have not used the bundle in awhile. Implemented my own but I'm surprised that it's hitting the oauth server on each request. If it is then this would in fact be a good use case for overriding the user provider. But I'd be surprised if it was really doing that just for user information.
Is it possible to create a page in asp.net that allow the access to a user that has a defined IPaddres? My goal is to add a page "test" (not linked to my website) and I want to define a rule that only a specified IP address can get the access.
How can I implement this throught asp.net?
You could try putting the page(s) in a separate folder and password protect it, then, give the password to your user, so they may access the content. You could go as far as password protecting each file. This helps if your website is password protected or has a login.
You could also create a sub-domain for that user specifically.
These are just a few. I'm sure you'll get better suggestions here on SO!
You could go for a programmatic solution. However, I would use IIS functions to block the access. Less code, easier to configure and no hassle on your developement/test environment.
Assumption: you are using IIS since it is ASP.NET. But other webservers should have similar solutions.
You can add IP restrictions to the directory (meaning you would have to put your page in a separate directory). Example here: http://www.therealtimeweb.com/index.cfm/2012/10/18/iis7-restrict-by-ip
Obviously there are a lot of other and arguably better ways to grant access to a page if what you really want is for a specific "user" or "group" to have access, but assuming that your really want the access control to be based on IP, the answer may still be dependent on peripheral concerns such as what web server you are using. IIS for example has some features for IP based security that you could check out.
Assuming though that you really, really want to check IPs and that you want to do it in code, you would find information about the calling environment in the Request of the current HttpContext, i.e. context.Request.UserHostAddress.
If you want to reject calls based on this information, you should probably do that as early as possible. In the HttpApplication.BeginRequest event you could check if the call is targeted for the page in question and reject the request if the UserHostAddress is not to your liking.
If you prefer to make this control in the actual page, do it in some early page event.
To manage the acceptable IP(s), rather than hard coding them into your checking code, I suggest you work with a ConfigurationSection or similar. Your checking code could be something similar to:
var authorizedIps =
authorizedIpConfiguration.Split(',').Select(ipString => ipString.Trim()).ToList();
isValid = authorizedIps.Any()
&& authorizedIps.Contains(context.Request.UserHostAddress);
If the check fails, you should alter the response accordingly, i.e. at least set its status code to 401 (http://en.wikipedia.org/wiki/List_of_HTTP_status_codes).
NB: There are a lot of things to consider when implementing security features, and the general recommendation would probably stand as "don't do it" - it's so easy to falter. Try to use well proven concepts and "standard implementations" if possible. The above example should not in itself be considered to provide a "secure" solution, as there are generally speaking many ways that restricted data can leak from you solution.
EDIT: From you comment to the answer given by nocturns2 it seems you want to restrict access to the local computer? If so, then there is a much easier and cleaner solution: Just check the Request.IsLocal property. It will return true only for requests originating from the local computer, see HttpRequest.IsLocal Property
(Also, you should really make sure that this "debug page" is not at all published when deploying your solution. If you manage that properly and securely, then perhaps you do not even need the access check any more. If you want debugging options in a "live" environment, you should probably look to HttpContext.Current.Trace or some other logging functionality.)
We have in one of our customisations implemented permission checks with dynamic authorities in Alfresco. When migrating to solr the search results for those nodes affected by our dynamic permissions became faulty. The reason seems to be that permission checks are done at query time, however our dynamic permissions are not taken into account :(
Here is a short explanations of how our dynamic authorities work:
Check if a node has an association to an authority, if the current user belongs to that authority (group) -> approve access. The node has a lot of different associations and everyone is checked and given READ or WRITE access depending on to which association it belongs.
Is there anyway to tell the Search service to do permission checking on the returned nodes instead (like lucene does)? One workaround I thought of would be to run the query as administrator, then iterate over the result and manually do the permission checks?
Could that be a way to solve it? Any other ideas you could share with me?
Alfresco will perform after-query permission checks on SOLR results when the security.anyDenyDenies property is set to true. This check will involve any dynamic authorities, i.e. it will be a standard check.
The main problem then would be to get the full results from SOLR without pre-filtering there. Other than setting the runAs user to System in a custom sub-class of org.alfresco.repo.search.impl.solr.SolrQueryLanguage (within / around super.executeQuery method call - bean(s) search.lucene.alfresco, search.solr.alfresco, search.fts.alfresco.index and search.solr.cmis in solr-search-context.xml), I see no simpler way to achieve this.
Note: This applies to Alfresco 4.2d and later - I don't know when after-query permissions for SOLR have actually been introduced, but they weren't present when 4.0 came out AFAIK.
Where I work we are designing a webapp in which users may belong to multiple groups and each group has access on a set of resources not known in advanced. Plus, users can enter or leave groups and groups can acquire or lose access to resources, so the whole permission granting system needs to be dynamic.
We are using Symfony2 and the FOSUserBundle.
We like how the ACL system works, but we could not find a way to apply it to the Group object.
Has anyone done something like that with Symfony? Or do you have any suggestion on how to implement it in other ways?
According to the cookbook, you can use the RoleSecurityIdentity instead of just the UserSecurityIdentity. So from my understanding of it your Role is your Group. Im working on a similar issue now. When have have done a little more with it Ill try and update this with some code snippets.
But for now have a look at: http://symfony.com/doc/current/cookbook/security/acl_advanced.html
EDIT:
We have gone in another direction and are instead going more with a permission per controller action system. So every controller action is assigned a permission name using annotations.
#SomeDomain/SomeBundle/Controller/SomeController.php
/**
* #Permissions(perm="some.name.for.the.node")
*/
public function indexAction(){ ... }
Then we have a permission bundle with a service that checks the permissions when a controller function is called. Our admins are given a GUI that will allow them to manage the permissions that groups will have and individual users.
Check out this gist that inspired what we are doing: https://gist.github.com/1391850
Im aware this isnt the acl system you were looking for but just thought i would update with what we are doing.