I am using Zend_Auth
for authentication in a web portal.
A normal mySQL "users" table with a login
and password
column gets queried against, and a user logged in.
However, I have two additional groups of users that I want to authenticate. All three of these user groups have their logon data in other tables. Their data is coming from external sources, so unifying these login accounts into one is not desired.
So it could be that a user is an authenticated user from any of the three groups, even all three of them, at the same time.
Every one of the three login groups has their own login form and logout button.
At the moment, I have a single, straightforward Zend_Auth
login, taken from some tutorial and slightly modified, that looks approximately like this:
function login($user, $password)
{
$auth = Zend_Auth::getInstance();
$storage = new Zend_Auth_Storage_Session();
$auth->setStorage($storage);
$adapter = new Zend_Auth_Adapter_DbTable(....);
$adapter->setIdentity($username)->setCredential($password);
$result = $auth->authenticate($adapter);
if ($result->isValid())
......... success!
else
.... fail!
where would I have to start to make this serve and address separate "logged in" states for the three groups? My idea is that I would like to share the session, and manage the authentications separately.
Is this possible? Maybe there is a simple prefix that makes this easy? Do any tutorials or resources exist on the issue?
I'm a relative newbie to the Zend Framework.
I took some inspiration from the Zym_Auth_Adapter_Chain, but altered it slightly so it doesn't stop on the first adapter that returns successfully.
To call it from a controller you simply create the chain, then the adapters you want to use (in your case this will probably be a DB adapter per entity table), and finally pass the adapters to the chain.
This is just basic example code, you probably want to use setCredentialTreatment also on the DbTable adapters...
The upside of this approach is that it will be trivial to add other existing adapters for other forms of authentication (ie. OpenID) to the chain later on...
The downside : as is you will get an array as result from every call to Zend_Auth::getInstance()->getIdentity();. You could of course change this in the Chain adapter, but that's left to you :p.
DISCLAIMER : I really don't think it's wise to do it this way. To make it work you have to share the same login and password accross the different tables, so if a user has more then 1 role (identity) changes his password you'll have to make sure this change is propagated to all identity tables where that user has an account. But I'll stop nagging now :p.
You should create your own Zend_Auth_Adapter. This adapter will try to authenticate against your three resources and will flag it in a private member variable, so you can know which of the logins attempts were sucefully authenticated.
To create your Auth Adapter you can take as basis the Zend_Auth_Adapter_DbTable.
So, in the __construct instead of pass just one DbTable adapter, you can pass the three adapters used in each resource. You'll do in that way only if each one use different resources, like LDAP for example, or even another database, if not, you can pass just one adapter and set three different table names in the configuration options.
Here is the example from Zend_Auth_Adapter_DbTable:
The method bellow, from Zend_Auth_Adapter_DbTable, try to authenticate against one table, you can change it to try in three tables, and for each, when you get sucess, you set this as a flag in the private member variable. Something like $result['group1'] = 1; You'll set 1 for each sucessfully login attempt.
You will return a valid $authresult only if one of the three login attempts were sucessfully authenticated.
Now, in your controller, after you try to login:
The key here is the line bellow, that will be implemeted in your custom auth adapter:
You can take as basis this form Zend_Auth_Adapter_DbTable:
This return the row matched in the login attempt when sucessfully authenticated. So, you'll create your getResult() method that can return this row and also the $this->result['groupX'] flags. Something like:
After all you can use Zend_Acl to take control over your views and other actions. Since you will have the flags in the Zend Auth Storage, you can use than as roles:
Here is some resources:
http://framework.zend.com/manual/en/zend.auth.introduction.html
http://zendguru.wordpress.com/2008/11/06/zend-framework-auth-with-examples/
http://alex-tech-adventures.com/development/zend-framework/61-zendauth-and-zendform.html
http://alex-tech-adventures.com/development/zend-framework/62-allocation-resources-and-permissions-with-zendacl.html
http://alex-tech-adventures.com/development/zend-framework/68-zendregistry-and-authentication-improvement.html
Why not just create a view that merge all 3 tables, then authenticate against that view?
Because Zend_Auth is a singleton, creating custom auth adapters for each authentication source only solves the first half of this issue. The second half of the issue is that you want to be able to log in simultaneously with multiple accounts: one of each authentication source.
I asked a similar question recently. The solution was to extend Zend_Auth as shown in the accepted answer. I then initialize the different authentication types in my bootstrap.
So, instead of the singleton
Zend_Auth::getInstance()
you would useZend_Registry::get('auth1')
, etc.