User rights in my cms - php

I am developing a cms as my hobby and i got stuck on something....In my mysql db i have different classes of users:Admins, normal users, veterans, premium etc.....Is there a way to create a php file wich contains settings for each user class? And then to use a function or something to check if a certain user has the right to...create a page for example....
For the moment i am checking the users rights with sessions...
If($_SESSION['user_type']=='Admin'||$_SESSION['user_type']=='premium'){
//do stuff
}else if()......... {
// ..............
}
but i want something like that
check_user_right(user_name);
if ($can_create_page) == true{
do......}else{....}

First of all, you should know that you should be storing user information in the database. Then, when someone logs in and you verify the login, you can store his or her user ID in the session, and then to get all other user information, like user_type, you would query the database based on that ID. Not sure if you're doing that yet, but you should be if you aren't.
As far as user rights go, you have two options.
The OOP Way
This is the one I recommend. It entails creating a User class that encapsulates all of the logic for retrieving a user from the database and subsequently checking if that user has a specific right.
class User {
protected static $_rights = array(
'admin'=>array(
'create_page','remove_page', etc...
)
);
public static retrieve($id) {
// Call to your database or persistent storage to retrieve user info based on id
return new static($retrieved_user_data);
}
public function has_right($right) {
return in_array($right, static::$_rights[$this->user_type]);
}
}
The Non-OOP Way
This is much lower-level and may be better for you in the meantime. Basically you would create an array of rights per user level that you store in the same file as the function you use to check them. Then this function must in turn be included on every page you plan to use it.
E.g., say you put the function in a file called functions.php, and it looks like this:
$user_rights = array(
'admin'=>array('create_page','remove_page','edit_user',...),
'veteran'=>array('ban_user','edit_page'),
// Other rights here
);
function has_right($user_id, $right) {
global $user_rights;
// Retrieve information from persistent storage about the user
// which I'm assuming you will store in $user_info
return in_array($right, $user_rights[$user_info['user_type']]);
}
Then you should include this file on any other file that you want to check user rights, and then all you need is the user ID (Stored in the session after log in) and the user type, which you can get from the database or other persistent storage.

Related

do I have to check login session when initiating PHP class?

I used to program php in procedural way. Since I would like to learn more about OOP I have decided to program php in OOP way for my new project.
Anyways, let's say I have a project that requires user to login. Which means in login.php once user enters the correct username and password, it will be redirected to index.php and will start loading all the products from the product table and display them nicely in index.php.
Before, how I did this was, in login.php I'll have the following code:
login.php
session_start();
...
if (loggedCorrect($user, $password)) {
$_SESSION['loggedinuser'] = $user;
//redirect to index.php
}
index.php
session_start();
if (isset($_SESSION['loggedinuser']) {
//select fields from products table and display them
...
}
so in OOP it will be something like:
login.php
session_start();
$user = new User($user, $password);
if ($user->hasCorrectLogin()) {
$_SESSION['loggedinuser'] = $user->getUsername();
//redirect to index.php
}
index.php
session_start();
if (isset($_SESSION['loggedinuser']) {
$products = new Products();
//display all products
}
Product class
class Products {
private $productArray;
...
__construct() {
//select all products from mySQL table then put every product in productArray
}
...
}
My question are:
when initiating object (like Products in my case). do I have to check login session? if so, should I do it inside __contruct? or should I do it before the "class Products" line?
I also have a cronjob.php, which will be executed every x minutes. When it's executing, it will create some objects like Products and analysis them. So if login session checking is required, then I'm not sure how to make this works, as cronjob doesn't support session.
Please advise
Quick answers
No. Your domain objects themselves should not be dependent on a logged in session; however, they may need a User instance to perform certain duties, such as only showing the products that a particular user is able to see.
Because of #1, this is now trivial.
Code review
First let's consider your login page code:
$user = new User($user, $password);
if ($user->hasCorrectLogin()) {
In this code, it would seem that User interacts with the database and has knowledge how to validate credentials. That seems a bit too much responsibility for a single class.
It could perform password validation by keeping the hashed password inside the object, but you would only need to validate a password once, so there's really no need to keep that field around. Another reason not to have it done here is when you need to consider strengthening your passwords on-the-fly, which could be a site policy to scale with growing hardware (e.g. when you're using bcrypt).
It should definitely not be doing database interaction; to separate both database interaction and password verification from the User class you could consider adding an authentication service.
try {
$user = $authService->login($userName, $password);
$_SESSION['loggedinuser'] = $user;
// redirect to index.php
} catch (InvalidLoginException $e) {
// oops, username or password invalid
}
Inside the authentication service, you could add another layer of abstraction to load the user record (using a data mapper for instance).
Instead of only storing the username in the session, you can store the whole User object as well. In some cases this may lead to inconsistencies, but it saves round trips to the database.
Now, let's observe the product overview page:
$products = new Products();
In terms of naming I would say that Products is not a good candidate to describe a collection of objects. A name such as ProductList or ProductCollection is better.
As with the authentication above, it's unclear how the Products class gets populated; it should come from some storage, so let's introduce the repository that will provide the list of products:
$productRepository = new ProductRepository($db);
$products = $productRepository->getAll();
In the simplest scenario, the repository gets initialized with a database instance; more levels of abstraction can be applied when necessary.

Sessions vs Configure at CakePHP

I saw some codes on internet which in order to check the permissions to access a concrete action, they use the Configure::read function in this way:
public function action1(){
if(!Configure::read('isAdmin')){
$this->redirect(array('controller' => 'depots', 'action' => 'status'));
}
//whatever
}
I was wondering, which is the difference between using Configure::read and Configure:write for this purpose and using $this->Session->read() and $this->Session->write()?
Which is a better way to check it?
Thanks.
Using the AuthComponent
If you make use of the built-in AuthComponent, CakePHP will store details of the currently logged-in user inside the session.
Getting properties of the currently logged-in User
Once logged in, you can access the information of the Used (e.g. role_id) via the AuthComponent. This can be done anywhere (also inside your Views or Models if desired);
For example;
if (123 === AuthComponent::user('role_id')) {
debug('hello admin user');
}
Or, inside a Controller:
if (123 === $this->Auth->user('role_id')) {
debug('hello admin user');
}
Accessing the logged in user
However, to dont have to repeat the group-id everywhere, it's best to creat a method for this (e.g inside your AppController);
/**
* Checks if the currently logged in user is an admin
*
* #return bool true if the current user is an admin
*/
protected function isAdmin()
{
// probably best to make the id configurable (Configure::write())?
return (123 === $this->Auth->user('role_id'));
}
Access control
To use a 'simple' authorisation, you can create your own isAuthorized() action in your Controller, which will allow you to block access to specific actions, based on the properties of the currently logged-in user;
Using ControllerAuthorize
I can't see why you would put the user role in the Configure array, as it is intended to contain application wide settings.
Personaly I have a table in my database that contain the roles. Although some roles may be added to it, there are some that I never modify (typically the administrator role).
This allows me to store its value as an application parameter in Configure and check for it later:
bootstrap.php
Configure :: write('administrator.role_id', 1);
TestController:
if($this->Auth->user('role_id') == Configure :: read('administrator.role_id'))
{
//do things specific to admin role
}
That said if the user role is stored dynamically in one way or another in Configure, it could probably work as well, but that's probably not the more elegant solution.

storing permissions into multi dimensional array php

OK, I am just trying to get better at making more loosely coupled classes etc in PHP just to improve my skills. I have a local test database on my computer and for the user table I have a column named "role". I am trying to build a function that is a general function for getting permissions for a user so it doesn't depend on a specific task they are trying to do.
When a user tries to do something such as create a new forum topic etc, I want to query the database and if "role" is a certain value, store permissions in a multidimensional array like the following:
$permissions = array(
'forums' => array("create", "delete", "edit", "lock"),
'users' => array("edit", "lock")
);
Then I want to be able to search that array for a specific permission without typing the following at the top of every PHP file after a user posts a form by checking isset($var). So if the user is trying to edit a user I want to be able to do something like the following via a class method if possible
if (Class::get_permissions($userID),array($permissionType=>$permission))) {
// do query
} else {
// return error message
}
How would be a good way to have a loosely coupled permission checking function that will be able to do something like this? It doesn't have to be laid out exactly like this but just be loosely coupled so it can be reused and not be bound to a certain task. But I want to be able to have an array of permissions instead of just "admin","user", etc for reusability and so it doesn't restrict my options down the road. Because I have a bunch of code that is like this right now in the top of my php script files.
if (Class::get_permissions($userID) == "admin") {
// allow query
} else {
// return error
}
Thanks for any input to help me get this to where I don't keep writing the same stuff over and over.
Your question is a little vague, but I will do my best. You said you're storing their permissions in an array $permissions.
public static $permissions = array();
public static function setPermissions($perms)
{
if (!is_array($perms)) {
throw new Exception('$perms must be an array.');
}
self::$permissions = $perms;
}
public static function hasPermission($section, $action)
{
if (array_key_exists($section, self::$permissions)
&& in_array($action, self::$permissions[$section])
) {
return true;
}
return false;
}
Using that logic, when you read a user's permissions from the DB, then set the Class::$permissions static var like so:
Class::setPermissions($permissions);
// ...
if (Class::hasPermissions($page, $action)) {
// user has permission
}
Note, my code is pretty generic and will have to remain that way until I have more information. For now, I'm assuming your permissions array is using a page section as the index and the array is a list of actions within that page section that the user has access to. So, assuming $page has been set to something like "forums" and the user is currently trying to perform an edit (so $action = 'edit'), the Class::hasPermission() function would return true.
I ran out of characters in the comments... But this is to your comment.
#corey instead of having a static object, I include a function that sets my permissions in the user's session. It as part of my LoginCommand class that gets called whenever the user logs in, obviously.
The permissions are then stored from view to view and I don't have to keep querying. The permissions check for most things only happen when the user logs in. However, certain sensitive things I'll run another query to double check. This has the disadvantage that, if the user's permissions change while the user has an active session, these changes won't be pushed to the user.
Remember to exercise good session security.
PHP Session Security
The only reason you wouldn't store data in your session size is because your session got too big. But unless you sessions are megabyte's, you probably don't need to worry about this.

Zend_Auth and dynamically changing user details on the UI

When my users are logged in I display their details (name, email) on the UI. When they update their profile, I would like to show the updated details, without requiring the user to log out and back in.
The UI details are retrieved from Zend_Auth via a view helper. Zend_Auth is storing the 'identity' details in a session.
How should I go about updating the details in the session?:
I was considering retrieving the user's login credentials from the database and using them to call Zend_Auth->authenticate() again. The problem is that I don't know the password, only it's md5 hash. I could consider a new method, reauthenticate(), which configured the adapter to bypass the md5 and salt, but this sounds laborious.
I was considering writing directly to the Zend_Auth session namespace, but this sounds like a recipe for trouble?
Have you come across a similar problem? How did you handle it?
Your ideas are much appreciated!
You can update Zend_auth identity for the currently logged user. Very simplified action that updates only username could be as follows:
public function editAction() {
// check if user is logged, etc, and then
// show the edit user form and process the data after submission.
$userForm = new My_Form_EditUser();
if ($this->getRequest()->isPost()) {
if ($userForm->isValid($_POST)) {
// process the submitted data,
// and when you are sure that everything went ok,
// update the zend_auth identity
$authData = Zend_Auth::getInstance()->getIdentity();
// this line would depend on the format of your
// identity data and a structure of your
// actual form.
$authData->property->nickname = $formData['user']['nickname'];
$this->_helper->FlashMessenger('Your data was changed');
return $this->_redirect('/');
}
}
$this->view->form = $userForm;
}
Hope this helps.
What I really want is a method on Zend_Auth::setIdentity($user).
But in the absence of such a method, I have used a hack in which I have create an auth adapter that always returns success and sets the identity to the same user object I would have created in a "real" auth adapter. Then I just call Zend_Auth::authenticate($adapter) with that adapter and it sets the identity internally.
Now, looking mosre closely at the internals of Zend_Auth::authenticate(), I see that what we could do is just:
Zend_Auth::getInstance()->getStorage()->write($user);
Here's how I solved the problem for the time being. Not sure yet if it's the best solution:
create a wrapper for Zend_Auth
include a getAuthAdapter($raw) method
configure the adapter differently, depending on the value of $raw
if (false === $raw) {
$this->_authAdapter->setCredentialTreatment('SHA1(CONCAT(?,salt))');
} else {
$this->_authAdapter->setCredentialTreatment();
}

Role of Session in user authentication/login?

I was hoping someone could help me with a question I've come up on.
I have a Session object that handles storage of general session data, I also have a Authentication object which validates a users credentials.
Initially I passed the desired Authentication class name to my Session object then had a login method that created an instance of the Authentication object and validate the credentials. I stored the result of this validation in a Session variable and made it available via a getter. The user data was also stored in the Session for later use. In addition to all this, I have a logout method, which removes the user data from the Session and thus logging the user out.
My question is what role should the Session object play in users logging into their account?
And what other ways might one suggest I go about handling user login, as it stands right now I feel as though I'm getting too much wrapped up in my Session object.
Simply calling your authenticate method should trigger logic within Auth to store the proper data in the session (or some other data store) and Auth should also be used exclusively to retreive/revoke this info. So using the example form your comment it might be:
class Auth {
public static function authenticate($identity, $pass)
{
// do lookup to match identity/pass if its good then
/* assume $auth is an array with the username/email or
whatever data you need to store as part of authentication */
Session::set('auth', $auth);
return true;
// if auth failed then
Session::set('auth', array('user'=>'anonymous'));
return false;
}
public function isAuthenticated()
{
$auth = Session::get('auth');
if(!$auth)
{
return false;
}
return (isset($auth['user']) && $auth['user'] !== 'anonymous');
}
}
[...] as it stands right now I feel as
though I'm getting too much wrapped up
in my Session object.
And id agree. Idelaly for authentication/credentials you shoudl only be interacting with the Auth/Acl object(s). They would then utilize the session as stateful store... but you shouldnt care that its even stored in session. The code utilizng the Auth/Acl object(s) should be completely unaware of this fact.
For example:
//Bad
if($session->get('authenticated', 'auth'))
{
// do stuff
}
// also bad
if(isset($_SESSION['authenticated']))
{
// do stuff
}
//Good
if($auth->isAuthenticated())
{
// do stuff
}
// inside $auth class it might look like this
public function isAuthenticated()
{
$store = $this->getSotrage(); // assume this returns the $_SESSION['auth']
return isset($store['authenticated']);
}
The session is a good place for holding user data that you want to have managed in some sort of state across various pages or if you need a fast accessible way to get at it without hitting the database. It is a bad idea to keep secure information (re: passwords/etc) in the session, but rapid access information like username, name, email address, preferences, etc is all good data to put in the session. Try to keep it simple though.
Keep in mind though, that the session (or related cookie) should only ever be used for identification. It should not be used for authentication.
Authentication object is a good method. Make sure that it only holds secure information as long as it needs to and that it has all the necessary functions available to keep sensitive data protected.

Categories