Zend Auth and ACL - php

I am hoping some can help me a little bit, I am currently developing my first site using a PHP framework, part of the site is spilt into a members area, this is where my confusion begins to surface, withing the members area I want normal members to be able to add new comments and edit there own comments, simple enough that I can just check the posters name against the username that is stored in the session, my confusion comes with differentiating between the 'normal' users and the higher level users who have the ability to delete and modify any ones comments etc, they should also be able to access the admin section of the site.
My question is should all user login through the same Zend_Auth controller, or should there be seperate controllers using Zend_Auth for each type of user or can all that be dealt with using Zend_Acl? Any help, advice, article, or tutorials would be greatfully appreciated. Personally I think the Zend documentation is a little raw on some classes.
Thanks in advance
sico87

I recommend the book "Zend Framework in Action" from Manning Publications as a great, up-to-date, introduction to this. It's available as PDF download, so you can have it now :)
But to answer this particular question:
Let's start by defining two key terms.
The "Auth" in Zend_Auth refers to Authentication, which proves someone is who they say they are (i.e. login).
The "A" in Zend_Acl refers to Authorization, which proves someone has the right to do what they're trying to do (i.e. access control).
Assuming the user has a single role...
Store the user's roles in the "identity" you get as part of Zend_Auth.
At login:
$auth = Zend_Auth::getInstance();
$identity = new stdClass();
$identity->user_pk = $user->getPrimaryKey();
$identity->user_name = $user->getName();
$identity->role = $user->getRole(); // select * from user_role where user_pk=xxx
$auth->getStorage()->write($identity);
In Controller:
$acl->add(new Zend_Acl_Resource('news'))
->allow('defaultRole', 'news');
Everything is denied by default, so you don't really need to specify:
->deny('defaultRole', 'news', 'add');
Further on in the Controller's code:
$identity = Zend_Auth::getInstance()->getIdentity();
if(!$acl->isAllowed($identity->role, 'news', 'add'))
{
header('Location: http://www.yoursite.com/error/unauthorized');
}
If the user's identity is not allowed to do "news->add", it will redirect them to the unauthorized page (assuming you've made such a page).
If the user had >1 role, you'd store an array of roles in their identity.
Then your check would go something like this:
$identity = Zend_Auth::getInstance()->getIdentity();
$isAllowed = false;
foreach($identity->role as $role)
{
if($acl->isAllowed($role, 'news', 'add'))
{
$isAllowed = true;
}
}
if(!$isAllowed)
{ // if NO ROLES have access, redirect to unauthorized page
header('Location: http://www.yoursite.com/error/unauthorized');
}
Hope that helps.

Yes, in most cases all of your authentication should go through the same controller. However, Zend Auth is not a controller type. Zend Auth is an API for utilizing common authentication methods like a database or http. Its job is really just to be a wrapper around the grunt work of writing authentication code.
Zend Acl is what you are looking for to distinguish between normal and privileged users. You only involve Zend Acl after the users have authenticated and logged in.
Most of what you need is in the ZF documentation. I read almost all of the documentation for Auth and Acl before it made great sense to me. Even though ZF's Auth, ACL, Storage_* and other classes are used very closely together, they all serve very distinct purposes. With a little time you will see that they build on each other nicely.
A couple of links to get you started:
Pádraic Brady's ZF Tutorial
Zend's DevZone article on ACL and MVC

I can understand why you are getting confused. I was/am still a bit confused. So, unfortunately I cannot answer your question directly. But, one thing i am doing in order to clarify all this stuff in my head is to think in terms of 'domain objects' as opposed to database records.
My tactic to deal with this issue is to create my own Auth Adaptor that is passed a 'User Base Object' along with the user credentials. My 'User Base' is kind of like a repository of users.
So the Zend Auth is left being 'an interface' to other Zend Components whilst i still have a bit more control over my system for storing and accessing 'Users'.
My User_Base class could be a wrapper around a Zend Db tbl or even just have some hard code in it that i can use for testing.
So in general-
design your own model of a 'user'
design your own Auth Adaptor - starting with the minimum interface required as outlined here: http://framework.zend.com/manual/en/zend.auth.html
and just keep it all simple and go slowly as you learn more about it.
well that's what i am gonna do anyway.
I aint even gonna bother with Zend ACL just yet til i have Auth clear in my head.
I'm revamping a legacy site and converting it to Zend MVC
These are some things (perhaps unconventional) that I have had to get to grips with for my 'model' to work. :
an app may be used by users from multiple 'user bases' - openID, legacy users table, new users table, fleeting guests, etc
a guest's identity might just be a hash created when they first arrive
whereas, a legacy user's identity might be represented by an id in the legacy users table
users and user_accounts are separate things. don't try to mix them into one concept cos it could get complicated.
there may be many different types of accounts in the system. I.e. Buyers Accounts versus Sellers accounts. Readers_Account versus Writers_Account
accounts 'have' users - 'primary account holder', 'admin super user', etc
the relationship between the users and an account are represented by, say, 'account_users' (a local subset of all users in all user bases)
roles arew attached to account_users (the users of that particular account).(As opposed to roles floating around )
don't be afraid to have more than one Zend application on a server to represent a website - e.g admin app, members app, front end app.
don't be afraid to let these apps use model objects stored in say 'shared models' folder, with the only model code that directly relates to the individual app sitting in the /application/models/foomodel folders.
each app might have its own custom Auth adaptor
an admin auth adaptor may only allow users from the 'admin users table' whereas a front end app's Auth adaptor might be able to authenticate users from the guest userbase, staff, or members user base.
might be a speical case where front-end apps session is cleared and replced by member session upon elevation when member logs in.
one user object per app per webclient at anyone time (as opposed to trying to reference a person with a guest user AND a member user - that's too complicated)
one session per user per app (namespaced to avoid conflicts with other apps that they may be logged into on that domain) - (as opposed to trying to simultaneously refer to 'the person using it' with a guest session AND a member session. again, that's too complicated)
ok i am starting to ramble....but you get the idea. Don't let the Zend_Auth+Zend Db tutorials that you see sway your own model. they are just simplified examples.
nuff said

I have a few questions about this piece of code
$auth = Zend_Auth::getInstance();
$identity = new stdClass();
$identity->user_pk = $user->getPrimaryKey();
$identity->user_name = $user->getName();
$identity->role = $user->getRole(); // select * from user_role where user_pk=xxx
$auth->getStorage()->write($identity);
$identity = Zend_Auth::getInstance()->getIdentity();
Are user_pk, user_name and role stored as cookies? Will someone that makes a cookie with the role-name able to access the secured parts of the websites? Shouldn't a password (with md5-encryption) be part of the identy as well so when can verify username and password with each request?

Related

Decouple user information and authentication information in Symfony

First off, I am new to Symfony, so I don't know the exact functionality of bundles like FOSUserBundle etc., as well as the terminology.
I am looking for a way to use the Symfony security component in a way that enables me to decouple a user's login credentials (say, a login name and a password, maybe the roles) from the actual user meta data (like first name, last name, groups, birth date, etc.).
The idea is that a user can login with different sets of login name/password and still be recognized as the same user (in the end that means, getting the same User object).
To me, this comes especially handy in combination with multiple authentication providers. For example, if I wanted to enable my users to login via an OAuth2 service as an alternative to logging in with their locally-hosted login name/password-combination (like StackExchange does, for instance), how would I do that?
I have read multiple pages of documentation of Symfony, e.g.:
https://symfony.com/doc/current/security.html
https://symfony.com/doc/current/security/entity_provider.html#create-your-user-entity
This latter one even says at 1) Create your User Entity, that a password is a field of User.
I have recently created just that, first I named my classes UserCredentials and UserDitails and because of the confusion of the getUser function i decided to rename UserCredentials to User. I agree with Alex Blex about the relation (manyToOne on the User side). When you decouple your login and metadata you will need to learn how to embed forms or creating your own form models, which is something I am currently working on and you might need to implement callback functions for deleting and updating entities. The more I work on my UserBundle, the more it looks like the FOSUserBundle. There is quite a bit of work of designing it to work well but it's great for learning. If you wish to inspect how the FOSUserBundle works, after you install it, you can find it in the vendor/friendsOfSymfony folder, it might provide a few answers.

User specific content in Symfony

I am currently working on a webapplication in Symfony. The application involves many clients which all have their own account to login with. For the user management I use Friends of Symfony User Bundle which I'm more than happy with.
In the application an Admin needs to see the information belonging to all the clients, where a client needs to get restricted to only be able to see his own information.
At this point FOS assigns the role "User" to all the accounts I register. I have considered to only give the client access to information belonging to him by using a query like;
$query = $this->getEntityManager()
->createQuery(
'SELECT c FROM clientsBundle:client c
WHERE c.name LIKE :string'
)->setParameter('string', '%'.$string.'%');
Then give var clientID the value of the clients id, and then get all the information needed according to that value (id).
But to be honest I don't really think this is the best practice.
I was wondering if there is maybe an (easier) option to not only allow the user to access certain pages through security.yml in Symfony, but also make the content in that page user specific.
Any help would be much appreciated.
we're currently working on a large web app that holds accounting information for users. So a similar thing where you only want your user to have access to their own data.
we simply write a number of verifyAccessTo methods that check that the entity that theyre trying to access belongs to their organisation (in our case a school) by assigning a relationship to that entity.
It might look something like this.
public function verifyAccessToTag( School $school, Tag $entry ) {
return $entry->getSchool()->getId() == $school->getId();
}
then when we're listing out data, we'll query specifically for entities relating to that school.
If you have specific area of a site that need particular access, such as admin areas, then in the firewall is the place to do it (security.yml).
If you need to sift and restrict on data, then the way you query and validate access on the specific data is probably the only way.
The whole world of security is a massive one, but heres some resources that might help.
securing services <-- this is really useful for ranked systems
deny access to content
voters
Hope that helps.
You can get the user's id and use that:
$user = $this->container->get('security.context')->getToken()->getUser();
$user->getId();

Using tank_auth with multi type user and HMVC

Using Tank Auth for first time along with HMVC. In my application there are 2 type of user one is say student and another is institute.
I created two modules for each user type and separated the tank auth library , both user's registration, login and tables are different from each other.
Now if I try to add any other page which is common to both users like home page, Which library should be used.
I know there must be better solution to handle multiple user problem.
Please let me know where I'm doing wrong. And what should I do to tackle this problem.
You're right, there's a better way to handle this. Duplicating your user / registration system is the wrong way to go.
You'll need to modify TankAuth to include a user type column, and then check for that user type. I'd suggest a new column in the 'users' table for 'user_role':
https://github.com/ilkon/Tank-Auth/blob/master/schema.sql
You could handle the user_type as either an int or enum. I'd lean towards int since enum is harder to change later. You could also add a new table for user_roles but I usually just store these in a config file.
Once the schema is altered, you'll need to add a reference to the new column (along with possible options) in the Tank_Auth code. You'll need to include it in creation, update (data is passed to model from the tank auth controller: controllers/auth.php) and lookup functions. I would add a lookup by user_role as well to the tank_auth model (application / models / tank_auth / users.php):
function get_user_by_role($role)
{
$this->db->where('LOWER(user_role)=', strtolower($role));
$query = $this->db->get($this->table_name);
if ($query->num_rows() == 1) return $query->row();
return NULL;
}
Lastly, you'll want to set the user role to session on login so that you can track the user type (and what content / functionality they have access to).
I've used Tank_Auth myself for several projects.
building on what calvin said, codeigniter does a good job a securing your application, tank auth will verify them, however you need different user levels, this usually falls under permissions. Your job as a developer is to make sure codeigniter does it's security checks via CSRF & XSS( I would suggest you do this in each validaton rule, rather than globally, especially If your admins need to add any tags not allowed suc as "script"). you can see how I personally setup my controllers regardless of my Auth library here...
You need to have a row in your users table called "permissions" which is either a serialized array or json encoded, or you can do a google search on permission bitmasking, which requires an int field

CodeIgniter authentication + user privileges

I'm trying to build an authentication system in my application, but I'm having some problems in deciding which is the best way I could acomplish what I want in CodeIgniter.
The website allows companies to manage their buildings. A company can have many buildings, and many users (when I say users I mean employees from that company).
In this website I would like two have (basically) four general kind of users.
Super Admin: This would be able to add new admins and new companies to the database, and give privileges to the rest of the admins.
Admin: This would be able to do different stuff depending on the assigned privileges.
Company Super User: This user would be created directly when an admin creates a new company. This user would be able to create new users for that company, and since s/he would have total permissions, he would be able to do everything that the other users can do.
Company User: Depending on the privileges assigned by its super user, this user would be able to do and see different data (for example, a simple user would just be able to see information from one of the many company buildings).
So, even though I've seen many authentication libraries out there for CodeIgniter, it would be nice to hear any recommendations about how I could design this "authentication role based" system, and if you particularly recommend a library that could help to accomplish this.
Appreciate!
There Are many libraries that already handle Authentication within Codeigniter, but the one I would recommend is Ion_Auth. It handles user permissions (groups) very well and I've actually done a detailed writeup outlining a good way to handle this situation with Ion_Auth.
I suggest FlexiAuth library which is a re-modified version of ion Auth, and has lot of features already built in, simply out of the box.
I've been developing a role based authentication system for Codeigniter called WolfAuth, here's the repository. It's still early days, but it sort of works. You can add roles, etc and then restrict functions and classes to particular user roles and usernames.
Use CI_aauth. I like this, this is very good from others auth.
https://github.com/kabircse/CodeIgniter-Aauth

What choices to make for an application backend

I am creating an web application and I at the point that i am starting to make backend choices. Now there are a lot of ways to go with this, so I am looking for some good points and back practices.
Some of the question i have involve:
Should i make a seperate table in the db for admin users
Should i extend make some classes to load the admin data and the normal data, or make seperate classes for the admin section
Where can i get some information on making different types of users
Just some best practices for a backend
My application is written in PHP with an MySQL database.
Keeping a separate table for admin users is nice, but only if those admin users aren't "regular" users as well - otherwise you'll step on your own toes trying to keep usernames/IDs unique but somewhat connected.
A couple things to consider:
Apache authentication (or Windows accounts on IIS) for admin users. Separate system entirely, but allows for overlap - a regular user can be a regular user, but they can't access any admin functionality until they authenticate through the browser. Works fine if you only have a couple specific kinds of user role (e.g. member & administrator only).
All users in one table, but with roles and permissions separate. This is the most flexible because you can get as granular as you need. For example, any user can "post comments," while an admin can "delete comments" and "ban users," but a moderator can only "suspend comments" and "mute users." As you add new features, it's simply a matter of implementing some new permissions & assigning them to the roles. Drupal's access control does this really well, worth a close look.
A good way to do it is to add a new field in the users table for 'rank' in order to differentiate between regular users and staff members, and possibly between the different staff member levels such as moderator, admin, etc. if you need it. Because an administrator should be able to perform all functions that a user can. Use
class Admin extends User { }
if you want to add additional functionality specific to staff members.
As for backend functions, that depends on how your site is set up. If you're using a framework, you can just add new functions to existing controllers and restrict access only to users with a certain rank.
For example, you might have a controller for ForumPost objects, but calling the ForumPost delete() function would require the user to be a forum moderator.
If you're not using a framework, you'll probably have to make your own pages for each backend function you need.

Categories