Symfony Access restriction to CRUD actions - php

I have simply CRUD function generated by symfony.
There is article class and article owner.
I want to prevent other users than owner of current article tu edit it.
I was thinking about custom my own filter or validator but when i will implement validator some of the users can enter into edit form (they couldn't only sent it).
But when I will implement user filter there will be problem to make filter execute only before some actions (edit in this case).
How should i do that?

I think this is built-in. You should read about the security.yml file.
UPDATE: I see... apparently the security system calls the method hasCredential() of the user object. Maybe you could extend tthis method in your custom user class, so that it does a special check when its parameter is, for instance, 'article_owner'.
Once this is done, all you'll have to do is specify this credential for the actions you want

I don't think symfony supports Object level access control out of the box. I had that particular problem in one of my applications and I ended up doing explicit check whether the logged in user matches the owner in the edit action. This is the function I used for that:
protected function hasObjectAccess($obj) {
if ($this->getUser()->hasGroup('admin')
|| $obj->getOwnerId() == $this->getUser()->getId()))) {
return true;
}
return false;
}

Related

Laravel policies: How to make a "on behalf of" behaivour

This is maybe a question on how Laravel works internally.
I'm writting an app. Only a logged user can create certain kind of records, that's easy, you just add $this->middleware('auth') to the controller, and that's it.
Now I want something more complex, the users with the role admin can create/edit that kind of records on behalf of some user. Imagine something like StackOverflow where a user can edit the question another user made, but for creation. That's it, an admin can create a post on behalf of the user():
So I have my create() in my PronController, it is something like:
function create($sid, $uid=NULL) {
// $sid is section id, where the post is going to be created... don't mind...
// if $uid (user id) is null, it will take the user from Auth::user()->id
$user = empty($uid) ? Auth::user() : User::findOrFail($uid);
// I want that only "admin" can use this $uid parameter, so I plan to use
// a Policy:
$this->authorize('create', $user);
}
The policy in PronPolicy is quite simple:
function create(User $authUser, User $user) {
return ($authUser->id === $user->id) || $authUser->isAdmin;
}
Now, I thought this should work, but it doesn't. It never reaches this edit() (I placed Log's)
So what I did is to change the $this->authorize() line to:
$this->authorize('createpron', $user);
And change the UserPolicy() (The UserPolicy!!!) to:
function createpron(User $authUser, User $user) {
return ($authUser->id === $user->id) || $authUser->isAdmin;
}
Now this works as I wanted. But I don't know why. Looks like Laravel searches for the object type in the parameter and then it activates the policy for that parameter, is it correct?
I don't know, although my code is working, it seems to me a bit dirty since the create "Pron" should be a policy of Pron, not user. Am I doing something conceptually wrong? what would be the right way to implement this?
Looks like Laravel searches for the object type in the parameter and then it activates the policy for that parameter, is it correct?
Correct! The docs mention this:
Policies are classes that organize authorization logic around a particular model or resource. For example, if your application is a blog, you may have a Post model and a corresponding PostPolicy to authorize user actions such as creating or updating posts.
By passing in the $user argument to $this->authorize(), you're asking if the current user can take an action against that particular record.
What you're doing isn't conceptually wrong (it is working), it just mixes a couple different authorizations together and as such feels kind of disorganized or unclear. Here's how I'd improve things:
Start by separating authorizations. You really have two separate but related permission checks happening:
Can the current User act on behalf of another User?
Can the end user (current or on-behalf-of) create a Pron?
#1 can be enacted as either a Gate or Policy, depending on if you want to pass in the on-behalf-of User for part of the check. That would be useful if, say, you can only act on behalf of Users within your own organization. The UserPolicy would be a good place for it.
#2 would be implemented as if you didn't have any on-behalf functionality. So maybe it's just return true because anyone can create them, or whatever your app's needs require for the ability to create a Pron.
Then, enact them separately.
function create($sid, $uid = null)
{
$user = Auth::user();
if (!empty($uid)) {
$user = User::findOrFail($uid);
$this->authorize('on-behalf-of', $user);
}
$this->authorizeForUser($user, 'create', new Pron());
// Continue your create logic...
}
Some benefits this provides:
Controller reads a little more explicitly for what authorization actions are happening, and how they're related
Gates and policies don't have to rely as much on mixing record types, and can strictly compare a permission to the specified user without arguments
Tighter control on permissions (e.g. if User X can't create posts, User Y acting on their behalf still can't create posts)
Possible down sides:
Opposite of tighter controls above: if you want to combine permission checks in order to modify them, this doesn't exactly solve that. For example, User X cannot create posts, but if an Admin is acting on their behalf then they CAN, the above doesn't exactly solve that

CakePHP: How to use a function with a model in every controller?

I have a project which includes admin and user section. Both section use the same controllers, just different functions and templates (ex: viewAdmin() and viewUser()). In function beforeRender() of every controllers, I set variable $admin as true for admin functions and false for user functions.
For authentication, I use Shibboleth. Shibboleth uses data from LDAP, while user types were saved in SQL-Database, that means while it can check if the login and password are false, it can't check if the user is admin or not. An user can go to ADMIN section as long as they use the right action (ex: go to the link http://example.com/tool/viewAdmin).
To prevent this, I will have to:
Load model Users
Compare the environment variable uid (login name) with the "login" columns in Users table in my SQL-Database
See the "type" column in Users table to know if user is admin or not.
Compare the result with value of $admin and redirect to an error page when necessary.
The problem is: I don't want to repeat those steps for EVERY controllers.
Currently I have 2 ideas:
Write a function in UsersController, and use it in every controllers.
Create a component and load it in every controllers.
Both methods require me changing code in all controllers. I would like to hear a better way with less work, perhaps by changing app.php or bootstrap.php.
Any suggestion is appreciated.
To share methods in CakePHP controllers you can do:
Create component and include in controller
Or create method in AppController and use it in child controllers
Or PHP way create Trait.
But when you authorize users, then all user data is stored in session, incl. is user roles (example admin, regular, member,.. )
Use the official CakePHP authentication plugin and extend the LDAP adapter with the additional code check you need. This is very easy to do and also a very clean way of solving the problem. Disclaimer: I'm one of the authors of the authentication plugin. https://github.com/cakephp/authentication
Or if you want to stay agnostic to any framework, use my library that is based on the authentication plugin and was decoupled from any framework but still works just nice with Cake https://github.com/Phauthentic/authentication.

User Roles and Permission in CodeIgniter 2.1.4

I am using this version of codeigniter 2.1.4 and I want to add user roles and permission. I am totally new for this framework I have done this in Zend but I am not able to find any library in codeigniter. I am also confused with Hooks.
Anybody will explain me what the purpose of hooks in a layman language. and also about the library with a small example with the same version so that it will be easy to understand.
Thanks.
Since you already have experience with the Zend ACL, why not use it in your CodeIgniter project? (Link)
Just set up your roles, resources, and permissions in your "MY_Controller.php" file so they're available to all your controllers. Also set up your user in MY_Controller (e.g. $this->theUser) for the same reason.
Set up classes for your resources in your Libraries folder that "implements Zend_Acl_Resource_Interface" and a "User" class for your user that "implements Zend_Acl_Role_Interface".
After setting up the ACL in MY_Controller, retrieve role(s) for the user from your database and add them to your user:
$roles = $this->theUser->getRoles(); // get the assigned role(s) for the user (array)
$acl->addRole($this->theUser, $roles); // then apply them to the user
With that done, I typically put something like the following at the top of each controller:
if ( !$this->acl->isAllowed($this->theUser, 'article', 'modify') ) {
redirect( '/home', 'refresh' ); // go back home
exit;
}
Don't forget, you can even set up dynamic assertions (i.e. implements Zend_Acl_Assert_Interface) if a permission to a resource requires some logic. I typically put assertion classes immediately following their related resource class.
Use Ion_Auth, it is an authentication library with a system of user roles. Should be easier for you to create permissions in your code.
This is only my 2-cents but Hooks are somehow similar to an event-driven approach. This means that they will be triggered at particular times in your code.
In the documentation, you can see that CI has 7 hooks ready. Thus, you can inject any script of yours at those 7 moments.
Let's say that you can add a script during the hook pre_controller that checks for the user's browser's language, so that in all your controllers you already know the language to use.
Note that ion_auth also supports hooks.

CakePHP ACL generating different links for different groups

Using CakePHP 2.0's ACL I have created 2 groups. One is admin and one is visitors. Right now admin can add and upload images and visitors can just view the images, if they click add or delete, it won't let them do anything. What's the best way to remove these links for visitor group? If I check which group they belong to using if/else statement, would that be the best solution?
To hide links that lead to actions a user is not authorized to perform, the views must somehow be aware of the user permissions.
You could check these permissions by checking the group a user belongs to, but this would mean that you wouldn't rely on the ACL permissions anymore. So any ACL permission update would have to be reported in code. Not very handy.
Then what else ? An approach is to check the user permissions in the controller, typically during login, and then keep these permissions in session.
The permissions in session can then be checked in the views to hide or show some parts of the views. You can find an example of this method here:
But for links specifically, you can go a little further and avoid to write the tests in views. I personnaly use a helper that inherits from the HtmlHelper and overrides the link() method.
Basically it works on the same idea: inside the overriden link() method, the permission on the target action is checked and the helper return the link, or nothing if the user is not allowed to access the target action.
If you want to try my code, you can use my Acl plugin
In your AppController, set the permissions:
var $components = array(..., 'Acl.AclManager');
function beforeFilter()
{
...
//you can put it here as the permissions check is performed only once per session
$this->AclManager->set_session_permissions();
...
}
And in your views, use the AclHtmlHelper
$this->AclHtml->link(...);
A general remark on the principle this method is based on though: all permissions are checked during login. If you have many actions in your application, this can considerably slow down the login.
A more effective approach could be to check the user permission for each actions only when it is required, meaning when the link() method is called. But this would mean that the helper would have to check the Acl permission itself, and this would somehow break the MVC model. And in the core lib, the Acl check is highly coupled to a component.

Creating a User Login System: Put logic in Code or Database

I am trying to create a login system thats generic so that it can be adapted for use in various apps. I decided that 2 main "parts" of the system will be User Meta Data & Roles/Resources/ACL.
1. Metadata
I thought of keeping most data like what meta data are available for users in the database, so that admins can manage them using some GUI.
Problem is how can I then configue how I want inputs to render (textbox, checkbox, radios etc.). Then another problem is validation, filters.
2. ACL
I think for simple ACL it will work fine. But suppose I want say users to be able to modify posts they own. In Zend_ACL that is accomplished with Assertions. I thought that will make a "simple" login system overlly complex? Also it will be hard to build I suppose?
Currently I have my database like
Logging in users: I recommend using a separate controller (call it Auth for instance) that has loginAction and logoutAction. Zend_Auth (Zend_Auth using database) will check the database for the right credentials. Once the user is verified, you will save it in the global accessible place(the Zend_Auth class has methods to do this). This is also a good moment to query which roles the user has and store them.
Metadata part of your application: I'm not sure what the question is exactly but I assume you want to store dynamic information about user and have a GUI for admins to manage this. Why you would render different types of controls? Validating the information can be done by defining a lot of the most common metadata (like Twitter) and create rules for them. In the save action for the metadata you would validate using these rules.
ACL: Resources rarely change, you are better off putting them in a configuration file (for speed). You should give a lot thought to resources: what are they exactly to you? Controllers? Modules? Create a plugin that will preDispatch every request checking the role of the logged in user against the requested resource. E.g.:
$action = $request->getActionName();
$controller = $request->getControllerName();
// role, resource, privilage
if (!$acl->isAllowed($user->role, $controller, $action) {
//go to access denied page!
}
Now that Zend_ACL is used for the global access rules, you are better off checking for specific access inside the action itself (like if ($loggedInUser == $article->author) {//edit the article};).
Also don't forget Zend_ACL can be integrated with Zend_Navigation to hide menu items users are not allowed to use (and more).

Categories