I'm pretty new to using CakePHP but I'm already finding incredibly useful for rapidly developing web apps.
However, I was wondering if there is a way to restrict access to certain objects in a non-standard way. For example, if I was to create a single CMS system allows users to create a "site", how can I assert that the users (multiples) have access to that particular site?
I could check this in my site controller but would I need to check this for every single controller on my site - for example, I would need to check that the current Page, News, Contacts, Files etc being edited belongs to the site ID and the user has access to edit it?
ie, thecms.com/pages/edit/123 (how can I be sure user 9 can edit page 123 which belongs to site 2)
I'm assuming this is outside of what ACL can offer as they're entity specific. Is there any easy way to do this?
I assume that you already know about CakePHP's Auth and ACL component, which can provide ways for restricting content. But it's also true what you say: that CakePHP's ACL is 'entity-specific' and not the best option for a 'per-record' basis (e.g. user 3 shouldn't access article 7). So I propose this code; try it and let me know:
Within the app/app_controller.php file:
<?php
class AppController extends Controller {
function checkPermission($aro, $aco, $loggedUserRole = 'User') {
if ($loggedUserRole != 'Admin') {
$permission = ($aro == $aco);
if (!$permission) {
$this->Session->setFlash('You cannot access that.');
$this->redirect('/somewhere');
}
}
}
}
Then, within the action that you want to restrict, put:
$this->checkPermission($this->Auth->user('id'), $someId, $this->Auth->user('role'));
So, the checkPermission() function does the following:
When called, you pass an id for the user you want to authorize, an id of the thing the user is trying to access, and also a role (so it is assumed that there is a column of 'Role' within the users table; also, $this->Auth->user('id') means the user session data automatically stored by the Auth component). The checkPermission() method then checks if the passed role is not an admin (supposing there will be admins who will have access to all), and then checks equality of both the $aro and $aco parameters. If not, then it redirects somewhere with a message of 'forbidden'.
Now, the $aco parameter can be a variety of things. For example, suppose you are making a function for editing a user's account, which takes an argument of $userId. So you compare the logged-in user's id (from $this->Auth->user('id')) with the passed $userId. If not equal, it means the logged-in user should not be editing that user record.
Another example:
You have an action for deleting an article, which accepts an $articleId argument. You can fetch the article from the database and then pass the article's user_id value as the $aco, before deleting the article. Again, the logged-in user would be kicked out if such user_id is not him.
I hope this solution serves you well.
Related
So I'm new to Laravel and trying to make a permissions system for the users on my application. Here is my approach:
1) Place a column in users table with the name 'permissions'
2) Create a table of permissions with columns id and page-name
Here's how it will work:
Each page will be assigned an ID. For example, the page Manage Accounts has id 1 and the page Manage Customers has the id 2 in the permissions table.
In order to give user full access to Manage Accounts and view only access to Manage Customers, I will make the following entry in the permissions column for the user 1.1111,2.1000
Now when the user will land on the Manage Accounts page, I will get the page id for the current page from the permissions table, i.e. 1. I will then convert the string value from the users.permissions column in the following format: array('1' => '1111', '2' => '1000');. Now I can get the user permissions saved against the ID of the page by $permissions['1'];.
I will then have a function to parse the 4 digits and get boolean values for the following in the exact order:
$canView = true;
$canAdd = true;
$canEdit = true;
$canDelete = true;
Now inside my page, I can easily put checks and display items accordingly.
Questions
1) So first question. Is this a good approach? Or are there better ways for going about this? I like this approach because I only have to add one more table in the database and it will only have as many entries as there are pages on my application, which aren't many. And it also means that I will only have to access the database once and I can then keep on using the values in the variable.
2) Should I create a separate class for permissions? I'm new so I don't completely understand the Eloquent class. But is that something I should be using for this? Or should I just add the functions that I need to create to the users class?
3) Where should I store the values of $canView, $CanEdit etc. Should I place them in the class for permissions and create an object for it? Or should I just use the Users class and access them using Auth::? I do not want to use Session, I don't think it to be safe.
4) Can I somehow have the permissions autoload every time a page is opened? I was looking into beforeFilter, and thinking of creating adding it to the constructor of each controller. Is that a good idea?
Thank you so much for your time and help.
Cheers
Why reinventing the wheel? take a look to https://github.com/Zizaco/entrust
I am developing a dynamic website using PHP. When a user of the website creates an account, a profile page should be created for that user. Say, a user called 'dev23' creates an account on my website, his profile should be accessible through the link www.mysite.com/dev23
How do I create such a thing? Should I create a standard page like userprofile.php which is populated with data specific to the username provided? Or should I create a permanent webpage for every user?
Please let me know the right approach to this porblem.
Is the www.mysite.com/dev23 meant to be public or only visible to the logged in user?
If it is only visible to the logged in user, you can create a myprofile.php file which retrieves the logged in user from the session and retrieves data accordingly.
If it is meant to be a URL that other users can hit, you probably want some sort of userprofile.php page with data passed along to identify the user to be viewed. For example, the url might be www.mysite.com/userprofile.php?user=dev23. If you are using Apache for your web server, you can look at using mod_rewrite to make the URL prettier. Thus, you could have the URL www.mysite.com/user/dev23 routed to userprofile.php?user=dev23 and your PHP processes the same. It is just a means of making URLs be more user friendly than a naked query string. This is common amongst many PHP-based CMS systems such as WordPress, Joomla, etc.
Ideally you should be creating a single file that handles all users.
Certain frameworks like SkyPHP allow this by defining the attributes after a valid page as "queryfolders" which can be used much like GET/POST variables.
If you are not using a framework, I might suggest you look into using one to simplify your tasks.
SkyPHP also has a functionality where a single field in a table can be used to pull this data simply by defining the page as _table.field_name_
It will check to see if there is a matching table and field to pull the data from and will automatically pull the id of the record whose field's value matches that of the url and assign it to a variable.
Example... If we have a table called category and a field named slug, one would create a page named _category.slug_.php
Then the url... http://mydomain.com/watches would look for "watches" in category.slug and pull back the identifier of the record as $category_id with $category_slug available also.
It would solve your issue if you are willing to give it a shot.
Again refer to the documentation here... http://switchbreak.com/skyphp
I'm creating a website in which users can create some profiles.
All profiles must be open for viewing only to users that the creator has chosen. The others won't be seeing them.
Using angular, you can easily create pages using routes, so of each new page you will have something like:
www.example.com/profiles/profile/1
www.example.com/profiles/profile/2
www.example.com/profiles/profile/3
etc.
But, say, you own profile 1,2,3 you can easily view profile/4, profile/5 etc...
How can you implement a system that prohibits viewing, or allows to see less data than the access-granded users?
Thank you.
As told, the answer should be server side. authentications should always be server side..
In your case, you need to query the database only once like you have done so far, actually the correct term will be just sending a http request to your api (as the http requests is doing the db queries). that http request should start by checking what kind of permissions you got and return the appropriate data (limited list of users, a specific user or an error that you don't have access to that specific content).
I hope it makes sense to you.
If using a database you can add a column AccessRights
0 = Basic
1 = Profile 1
2 = profile 1/2
etc
Different integers of AccessRights will let you access different things.
and to stop people with access rights 1 from accessing accessrights 3 material
if ($Accessrights < 3)
{
die("You Cannot View This");
}
it will be up to you to assign a variable for $Accessrights or something.
Hopefully this is something your looking for
So do I have to query the database on each page a user visits? Wouldn't that be too resourceful?
The access system that I want to create is something in the same vein as facebook.
You can see your pages and your friends pages, but you cannot see the private pages.
You can edit your profile, but not othe peoples profile.
Is this the right way to go?
You could check if the user is viewing his own record or if he is allowed to view any record
$iUserType = USER_TYPE_ADMIN; // constant
$iUserId = 5; // this and user type can be stored in session after login
$iViewProfileId = 5; // this should come from the request parameters
if (($iViewProfileId != $iUserId) AND (USER_TYPE_ADMIN != $iUserType)) {
// error, user is not permitted to view the record
}
I am developing an application in php codeigniter. Now I am worrried abt the permission.
I need page wise permission, page may be add records page, edit page, delete page and print report etc. There will be many users as well, and applicaiton will grow with passage of time.
If I implement ACL that will better for me or not
what can be ideal for me any suggestion.
First, let's clear up some terms: I personally use the security term for things like preventing SQL injection, XSS attacks, where we have to validate input, filter/sanitize values, take care of the dynamically generated SQL commands, take care of properly escaping output (for JSON or HTML text or HTML attributes), etc. This is not about what you are asking, if I understood well.
The access control or permissions system is where you give or deny access to a function for a user. It can be secure or not. I understand that to deny a user which does not have permission the access to a function may sound like "security", but I wouldn't use this specific word in this context, to avoid confusion.
Now, the answer:
I strongly recommend you create a few base controller classes to your needs. Read the following blog post carefully (it is short and useful): http://philsturgeon.co.uk/blog/2010/02/CodeIgniter-base-Classes-Keeping-it-DRY
A code to check if the user is properly authenticated (logged in) is essential. If the user is not logged in, redirect to home page or login page.
For fine-grained control, you could create your ACL in the database using the users table, plus an actions table, plus an acl table...
The users table would contain the users data (id, name, login, password, etc)
The actions table would contain the id field and at least one more field containing what suits best for your application: it can be only the controller class name (the first part of the URL, for example: "products"), granting access to the whole "products" controller or not. Or you may want to include both the controller class AND the method name (the first and second parts of the URL, for example: "products/add" and "products/delete"), and so on.
To decide about the actions table is the most decisive step. Think very well about it, balance your needs (your "true" needs)... I developed a system where each and every action has its entry. It is good, but it needs work to be maintained.
A very useful column for the actions table is a human-readable description of the action.
The acl then would be nothing more than a column for the user id and another column for the action id.
A "master" grant/deny access field in the users table is useful too, in case you want to temporarily deny access from a specific user, without having to delete all his permissions and maybe having to restore it later.
With the database tables and your "controller/method" or "actions" strategy well defined, you can easily code in your base controller class a function which checks if the user have permission to execute the requested action.
This is the basic. In my system, I have the users administration interface, where I can grant/deny the actions for each user (I use an ExtJS tree with checkboxes). One of these actions is the own user management. I have gone one step further, where the user who can access the user management may "delegate" (grant/deny) to other users only the actions he himself has access to.
The system has several modules, and functions. The interface does not show anything the user does not have access. So, I have users who can see only a single or a couple of modules, and they don't even imagine the existence of the other modules.
It requires more work to manage all this, but the result worths.
I also log each granted access, so it is possible to track who did what, and when. This log feature is very very easy to add, since you have this base controller "master function" allowing or disallowing the users to perform the actions.
I hope I have helped. I've just shared a bit of what worked (and works) for me...
I am very curious because I would like to be able to check this myself on my own site, as I am currently in the process of designing it. An example would be:
www.somesite.com/product.php?id=1356
When using Facebook, a user can change it and they get the user associated with this id. But in other sites, specifically Ecommerce sites, when I change it, it either fails or goes to the homepage.
There isn't any way to see if the user changed it. This is part of secure coding. From the server's perspective, you need to validate all of your inputs, and validate that the current user actually should have access to the resource they're requesting.
See https://www.owasp.org/index.php/Top_10_2010-A4 for some additional details and examples.
Facebook may seem to allow this only for the example that you've given because the user profile ID that you're attempting to access may be public to you. However, you won't have access to all other user profiles - only user profiles that you have permission to access. If you tried to access my Facebook profile ID, you would also see your access be denied here.
Since this is tagged as e-commerce, you should also be aware of the PCI DSS if you aren't already - where 6.5.4: "Insecure direct object references" applies specifically to this scenario.
When using Facebook, a user can change it and they get the user associated with this id. But in other sites, specifically Ecommerce sites, when I change it, it either fails or goes to the homepage.
Facebook does the same thing.
https://www.facebook.com/profile.php?id=102934810293841029348 goes to an error page titled "Profile Unavailable", because that ID doesn't exist.
You're likely just changing it to nonexistent IDs.
That works via $_GET method (or $_REQUEST)...
The reason you can change some site id (or any other parameter which is part of the url), and it works, is that because they programmed it to behave like that. It actually depends of how this url parameter is used in the background. For example, in product.php you will have something like this:
if(isset($_GET['id']) {
$id = $_GET['id'];
$id = filterid(id)..... and so ...
// Maybe check for id and redirect if id is not ok
// Maybe check for id and some additional secrete parameter ...?
// What is the id? What kind of behavior you want?
}
Reason why you have different behaviours across different websites - in dependence of url parameters (in this case "id") - is because different behaviours are implemented under different circumstances...
Some of them implement strict checks (especially for id's) because of the security!? For example, if you have page and you know that your id must be a number, and you know, that the max id in your database is for example 15000, you can write something like this....
if(isset($_GET['id'] && strlen($_GET['id']) <= 5 && isNumeric($_GET['id']) {
//if everything is ok you can execute your code here
}
else {
$id = 1; //if someone try to put something else in id, you will simply redirect him on first id(firs product)
}
That is just one example of behaviour. Now consider what else can be done? What do you want to do? How do you want it to behave? What kind of behaviour you will implement on your side - in dependencie of the parameters within the url is to totally up to you. User can follow up your logic on your web app by clicking on your predefined links - or he can manipulate with the url how ever he wants. You dont have possibility to check this. All what you can do is properly validate all of the inputs (no matter are they coming from the URL or some kind of post request)