I have a scenario where i need to check some additional columns while doing the authentication. This is because, the application stores some usernames in database and some in LDAP. the authentication precedence is for usernames in database. If username exist in database, we will not check in LDAP else we will check it in LDAP.
For LDAP users, we are keeping a copy of there usernames in same "user" table with a blank password column. To disgusting both group of users, there is an additional column called userDirectory with values "LDAP and INTERNAL". we have to keep a copy of LDAP usernames for application specific settings and all.
Also username+userDirectory is a uniqueKey
Now my problem is, sometimes there will be multiple users with same username but in different userDirectory. as mentioned above LDAP users will not have a password stored in database and that authentication is a separate code snippet.
I am using the below code for DB authentication. Even though i am adding a condition setCredentialTreatment('md5(?) AND userDirectory="internal"'), it is searching LDAP users also. HOW do i restrict this for userDirectory='internal'
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
$authAdapter->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password')
->setCredentialTreatment('md5(?) AND userDirectory="internal"');
$authAdapter->setIdentity($username);
$authAdapter->setCredential($password);
I have changed your code:
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
$authAdapter->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password')
->setCredentialTreatment('MD5(?)'); // changed
$authAdapter->setIdentity($username);
$authAdapter->setCredential($password);
$authAdapter->getDbSelect()->where('userDirectory = "internal"'); // added
http://framework.zend.com/manual/1.12/en/zend.auth.adapter.dbtable.html
check the last code under Advanced Usage By Example, code is as follows
$registry = Zend_Registry::getInstance();
$DB = $registry['DB'];
$authAdapter = new Zend_Auth_Adapter_DbTable($DB,'usertable','username','password');
$authAdapter->setIdentity($request->getParam('username'));
$authAdapter->setCredential($request->getParam('password'));
$select = $authAdapter->getDbSelect();
$select->where('`active` = 1');
$result = $authAdapter->authenticate();
if($result->isValid()){
//set user proper to zend instance
$this->_redirect('/index');
}
else
{
//logout or redirect to same page
}
Extends Zend_Auth_Adapter_DbTable and override _authenticateCreateSelect() method like this
protected function _authenticateCreateSelect()
{
$select = parent::_authenticateCreateSelect();
return $select->where('userDirectory = ?','internal');
}
Related
I am stuck with this problem. When the login credentials are authenticated in my zend application , I also want to check if the account has been confirmed or not. Confirmed is a boolean column in my account table and is set to False by default. I am trying to achieve this through following code..but it is not working
$db = Zend_Db_Table::getDefaultAdapter();
$authAdapter = new Zend_Auth_Adapter_DbTable($db);
$authAdapter->setTableName('Account');
$authAdapter->setIdentityColumn('Email');
$authAdapter->setCredentialColumn('Password');
$authAdapter->setCredentialTreatment('Confirmed = 1');
$authAdapter->setIdentity($data['email']);
$authAdapter->setCredential($data['password']);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if ($result->isValid()) {
if ($data['public'] == "1") {
Zend_Session::rememberMe(Zend_Registry::getInstance()->constants->sessiontime);
} else {
Zend_Session::forgetMe();
}
return TRUE;
} else {
return FALSE;
}
Despite the account not confirmed the authentication passes. Please tell me where am I wrong
The credential treatment parameter specifies how the password should be checked. You can override this to add additional clauses, but you still need to include the password bit. Really I wouldn't have expected your method to authenticate any users, so this may not be the main issue, but try:
$authAdapter->setCredentialTreatment('MD5(?) AND Confirmed = 1');
Changing the MD5 bit for however your passwords are encrypted. That should generate a query along the lines of:
... WHERE Email = 'xxx' AND Password = MD5(?) AND Confirmed = 1
I have made a login system through zend auth here is the code
// userAuthentication
public function authAction(){
$request = $this->getRequest();
$registry = Zend_Registry::getInstance();
$auth = Zend_Auth::getInstance();
$DB = $registry['DB'];
$authAdapter = new Zend_Auth_Adapter_DbTable($DB);
$authAdapter->setTableName('user')
->setIdentityColumn('user_name')
->setCredentialColumn('user_password');
$username = $request->getParam('username');
$password = $request->getParam('password');
$authAdapter->setIdentity($username);
$authAdapter->setCredential($password);
$result = $auth->authenticate($authAdapter);
if($result->isValid()){
$data = $authAdapter->getResultRowObject(null,'password');
$auth->getStorage()->write($data);
$this->_redirect('/login/controlpannel');
}else{
$this->_redirect('/login/login');
}
}
This work fine now. There is user_id (column) in user (table) where there are username and password too. I need to get that specific user_id from this table which just login and put it in session through
$user_session = new Zend_Session_Namespace('user_session');
$user_session->username = $username;
$user_id->user_id = $user_id;
so that I can query some info against this $user_id and pass the result into view (name) controlpanel
Get user id from storage :
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
echo $userInfo->user_id;
While this was already answered, I tend to use the getIdentity() function more frequently than the getStorage()->read() chain. Examples below.
// to check if authenticated
Zend_Auth::getInstance()->hasIdentity();
// to actually get the details from storage
Zend_Auth::getInstance()->getIdentity()->user_id;
// if I need to use the identity over and over
$identity = Zend_Auth::getInstance()->getIdentity();
$userId = $identity->user_id;
You can access the data the way Teez suggest or just pull it from Zend_Session_Namespace.
15.1.3.1. Default Persistence in the PHP Session By default, Zend_Auth provides persistent storage of the identity from a successful
authentication attempt using the PHP session. Upon a successful
authentication attempt, Zend_Auth::authenticate() stores the identity
from the authentication result into persistent storage. Unless
configured otherwise, Zend_Auth uses a storage class named
Zend_Auth_Storage_Session, which, in turn, uses Zend_Session. A custom
class may instead be used by providing an object that implements
Zend_Auth_Storage_Interface to Zend_Auth::setStorage().
Zend_Auth_Storage_Session uses a session namespace of 'Zend_Auth'.
This namespace may be overridden by passing a different value to the
constructor of Zend_Auth_Storage_Session, and this value is internally
passed along to the constructor of Zend_Session_Namespace. This should
occur before authentication is attempted, since
Zend_Auth::authenticate() performs the automatic storage of the
identity.
assigning an array to a session, you must provide a name to the session you area creating, i.e. you must do setStorage before you do getStorage.
you must write your code like this:
// userAuthentication
public function authAction(){
$request = $this->getRequest();
$registry = Zend_Registry::getInstance();
$auth = Zend_Auth::getInstance();
$DB = $registry['DB'];
$authAdapter = new Zend_Auth_Adapter_DbTable($DB);
$authAdapter->setTableName('user')
->setIdentityColumn('user_name')
->setCredentialColumn('user_password');
$username = $request->getParam('username');
$password = $request->getParam('password');
$authAdapter->setIdentity($username);
$authAdapter->setCredential($password);
$authAdapter->setStorage(new Zend_Auth_Storage_Session('User_Auth'));
$result = $auth->authenticate($authAdapter);
if($result->isValid()){
$data = $authAdapter->getResultRowObject(null,'password');
$auth->getStorage()->write($data);
$this->_redirect('/login/controlpannel');
}else{
$this->_redirect('/login/login');
}
}
and then to get your storage value, you must use this:
$x = new Zend_Auth_Storage_Session('User_Auth');
$y = $x->read();
and you get everything in $y as an object.
Enjoy!
This is my approach and it s working nice:
1-i start by defining an init function in the bootstrap
protected function _initSession()
{
$UserSession = new Zend_Session_Namespace('UserSession');
$UserSession->setExpirationSeconds(/* you may fix a limit */);
Zend_Registry::set('UserSession', $UserSession);
}
/* in the Login action,after correct username & pwd */
// Create session
$UserSession = Zend_Registry::get('UserSession');
// Get the user from database
$db = Zend_Db_Table::getDefaultAdapter();
$user = $db->fetchRow("SELECT * FROM user_table WHERE user_email = '".$user_email."'");
//then you assign to $user to $UserSession variable :
$UserSession->user = $user;
//finaly don't forget to unset session variable in the Logout action ...
user = Zend_Auth::getInstance()->getIdentity();
if(!#$this->user){
$objSession->errorMsg = " Please Login First .. ! ";
$this->_redirect('/user/login');
}
?>
I'm having a difficult time understanding how Zend_Session_Namespace is integrated with Zend_Auth. I have this method I'm using as the action to Authenticate my login page-it is working correctly and redirecting to the /monthly view:
public function authAction(){
$request = $this->getRequest();
$registry = Zend_Registry::getInstance();
$auth = Zend_Auth::getInstance();
$DB = $registry['DB'];
$authAdapter = new Zend_Auth_Adapter_DbTable($DB);
$authAdapter->setTableName('users')
->setIdentityColumn('UserName')
->setCredentialColumn('Password');
// Set the input credential values
$uname = $request->getParam('UserName');
$paswd = $request->getParam('Password');
$authAdapter->setIdentity($uname);
$authAdapter->setCredential($paswd);
// Perform the authentication query, saving the result
$result = $auth->authenticate($authAdapter);
// TRYING TO SET THE NAMESPACE
$this->session = new Zend_Session_Namspace('UserName');
if($result->isValid()){
$data = $authAdapter->getResultRowObject(null,'password');
$auth->getStorage()->write($data);
$this->_redirect('/monthly');
}else{
$this->_redirect('/login');
}
}
But I need to be able to store UserName as a Zend_session and call it from monthly controller. I'm not doing things right because I just get a blank screen when I try and do this:
public function indexAction()
{
$this->view->userName = Zend_Session_Namespace('UserName');
}
With the lines:
$data = $authAdapter->getResultRowObject(null,'password');
$auth->getStorage()->write($data);
You're writing all the user's information, except the password, which is OK. Where ever you need to access the logged in user's details, you can do something like (updated as per your comment):
public function indexAction() {
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity()) {
$userData = $auth->getIdentity();
$this->view->user = $userData;
}
}
in the view file (index.phtml) just: echo $this->user->firstname
That's it. If one day you decide to change the storage for Zend_Auth from session, to, for example, database, this piece of code will still work.
Youre not useing the correct namespace. Zend_Auth use the Zend_Auth namespace. The namespace is the structure, not the key for a value. so your session looks something like this:
Array('Zend_Auth' => array ('UserName' => 'myname')
Well thats not accurate exactly because you havent stored the user name unless youve provided for this directly in your adapter. youll need to do something like:
$auth->getStorage()->UserName = 'myusername';
Then you can access with $authData = new Zend_Session_Namespace('Zend_Auth'); $username = $authData->UserName;.
Take a closer look at how the Zend_Auth_Adapter_Db works.
This is my approach and it s working nice:
1-i start by defining an init function in the bootstrap
protected function _initSession()
{
$UserSession = new Zend_Session_Namespace('UserSession');
$UserSession->setExpirationSeconds(/* you may fix a limit */);
Zend_Registry::set('UserSession', $UserSession);
}
/* in the Login action,after correct username & pwd */
// Create session
$UserSession = Zend_Registry::get('UserSession');
// Get the user from database or just from fields
//you have to make sure that the psswd is encrypted use MD5 for example..
$db = Zend_Db_Table::getDefaultAdapter();
$user = $db->fetchRow("SELECT * FROM user_table WHERE user_email = '".$user_email."'");
//then you assign to $user to $UserSession variable :
$UserSession->user = $user;
//finaly don't forget to unset session variable in the Logout action ...
So I am using Zend_Auth to authenticate users of my website. Currently they are only able to log in with their email as login but I would like to enable them to log in also with their username.
Here is some code:
// prepare adapter for Zend_Auth
$adapter = new Zend_Auth_Adapter_DbTable($this->_getDb());
$adapter->setTableName('users');
$adapter->setIdentityColumn('email');
$adapter->setCredentialColumn('password_hash');
$adapter->setCredentialTreatment('CONCAT(SUBSTRING(password_hash, 1, 40), SHA1(CONCAT(SUBSTRING(password_hash, 1, 40), ?)))');
$adapter->setIdentity($request->getParam('email'));
$adapter->setCredential($request->getParam('password'));
Notice the line:
$adapter->setIdentityColumn('email');
How can I add also username there (column in the database called username, too)?
UPDATE:
This is how I solved this:
$login = $request->getParam('email');
$validator = new Zend_Validate_EmailAddress();
if (false === $validator->isValid($login)) {
$u = $this->_getTable('Users')->getSingleWithUsername($login);
if (null === $u) {
throw new Exception ('Invalid login and/or password');
}
$login = $u->email;
}
// prepare adapter for Zend_Auth
$adapter = new Zend_Auth_Adapter_DbTable($this->_getDb());
$adapter->setTableName('users');
$adapter->setIdentityColumn('email');
$adapter->setCredentialColumn('password_hash');
$adapter->setCredentialTreatment('CONCAT(SUBSTRING(password_hash, 1, 40), SHA1(CONCAT(SUBSTRING(password_hash, 1, 40), ?)))');
$adapter->setIdentity($login);
$adapter->setCredential($request->getParam('password'));
I deal with the same thing, and I handle it before Zend_Auth. I use a single user sign-in field and first check whether it's an email address -- if so, it's converted to the appropriate username. Then, let Zend_Auth do its thing.
This works well for me, although you'll need to kinda switch it around, since you're going the other way.
i. Add a filter to your user sign-in field, like this:
$user_field->addFilter('EmailToUsername');
ii. The filter:
<?php
/**
* Converts an email address to the username.
*/
class Prontiso_Filter_EmailToUsername implements Zend_Filter_Interface
{
public function filter( $value )
{
if ( Zend_Validate::is($value, 'EmailAddress') ) {
$user_table = new Users();
$user = $user_table->findByEmail($value);
if ( $user ) {
return $user->username;
}
}
/**
* Nothing happened, so don't filter.
*/
return $value;
}
}
As for just changing a Zend_Auth setting instead, Zend_Auth doesn't like either/or identity columns, so you'd have to write your own auth adapter.
My own solution:
$adapter->setIdentityColumn(stripos($indentity, '#') ? 'email' : 'username');
Fast and simple!
I am looking to register a reference to the main Database Adapter in the Registry during Bootstrapping so it can be used elsewhere in my site (specifically the Authorisation action).
I have implemented an ugly fix where i create a Database Table object and call the getAdapter() method on it and pass through that. However, this is a bad way of doing it and I would like it to be available via the registry.
Does anyone know how to do this? Any help or pointers in the right direction are appreciated!
I'm using Zend Framework 1.8.
If you're using Zend Framework 1.8+, and created your project with the command line tool, then it's as simple as registering your database settings in your application.ini config file.
resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "your.database.host"
resources.db.params.dbname = "database_name"
resources.db.params.username = "username"
resources.db.params.password = "password"
resources.db.isDefaultTableAdapter = true
If your database settings are preceded by resources.db you won't even need to do anything in your Bootstrap.php file because it will do it for you. Also, by setting the isDefaultTableAdapter setting to true, you can get an instance of your database adapter anywhere in your application.
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
Thanks for the replies. Ive decided to change the accepted answer and post the solution I finally used - which is insanely simple in the end!!
This is basically based on Dcaunt's comment...
In the bootstrap class..
protected function _initDb()
{
$resource = $bootstrap->getPluginResource('db');
$db = $resource->getDbAdapter();
Zend_Registry::set("db", $db);
}
Then access that elsewhere with...
$dbAdapter = Zend_Registry::get("db");
Thanks for the help and hopefully this helps someone else.
Your missing the best thing :)
If you use the Zend_Db_Table models (you should be) etc then you can set up a default adaptor - this way when you instantiate a model the DB connection it taken care off - this way you dont really need to save it in the registry or bother about connection before running a query through the model.
I do save it in the registry for later use if needed though - but I may remove this
protected function _initDB()
{
// Check that the config contains the correct database array.
if ($this->_config->db) {
// Instantiate the DB factory
$dbAdapter = Zend_Db::factory($this->_config->db);
// Set the DB Table default adaptor for auto connection in the models
Zend_Db_Table::setDefaultAdapter($dbAdapter);
// Add the DB Adaptor to the registry if we need to call it outside of the modules.
Zend_Registry::set('dbAdapter', $dbAdapter);
}
}
My 2 cents...
How to grab the default DB Adapter:
From Bootstrap:
<?php
$dbResource = $this->getPluginResource('db');
db = $dbResource->getDbAdapter();
var_dump($db);
?>
From a Controller there are two methods:
<?php
// Method 1
$bootstrap = $this->getInvokeArg('bootstrap');
$dbResource = $bootstrap->getPluginResource('db');
$dbAdapter = $dbResource->getDbAdapter();
var_dump($dbAdapter);
// Method 2
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
var_dump($dbAdapter);
?>
Check the zend-documentation at :
15.5.3.3. Storing a Database Adapter in the Registry
http://framework.zend.com/manual/en/zend.db.table.html
$db = Zend_Db::factory('PDO_MYSQL', $options);
Zend_Registry::set('my_db', $db);
// Later...
$table = new Bugs(array('db' => 'my_db'));
something like that you're looking for?
Edit:
to load your configuration from an ini-file, use:
parse_ini_file($inifile)
;configuration.ini
host = 127.0.0.1
user = username
password = blabla
;yourfile.php
$options = parse_ini_file('configuration.ini');
$db = Zend_Db::factory('PDO_MYSQL', $options);
I have a method in my bootstrap to add the adapter to the registry. I'd prefer a cleaner solution, but it works:
protected function _initRegistry(){
$this->bootstrap('db');
$db = $this->getResource('db');
$db->setFetchMode(Zend_Db::FETCH_OBJ);
Zend_Registry::set('db', $db);
}
Here is what i do:
Inside the bootstrap:
define('CONFIG_FILE', '../config/general.ini');
define('APP_MODE', 'development');
Inside the Initializer:
/**
* Initialize data bases
*
* #return void
*/
public function initDb ()
{
$options = Zend_Registry::get('conf');
$db = Zend_Db::factory($options->database);
$db->query(new Zend_Db_Expr('SET NAMES utf8'));
Zend_Registry::set('db', $db);
}
public function initConfig ()
{
if (file_exists(CONFIG_FILE) && is_readable(CONFIG_FILE)) {
$conf = new Zend_Config_Ini(CONFIG_FILE, APP_MODE);
Zend_Registry::set('conf', $conf);
} else {
throw new Zend_Config_Exception('Unable to load config file');
}
}
And finaly my config file looks like this:
[production]
database.adapter = pdo_Mysql
database.params.host = db.example.com
database.params.username = dbuser
database.params.password = secret
database.params.dbname = dbname
; Overloaded configuration from production
[development : production]
database.params.host = localhost
database.params.username = root
database.params.password =
Take a look at:
Zend_Db::Factory()
Zend_Config_Ini
Zend_Registry
If you are using Zend Framework 1.8 just do something like this in your controller/action:
class CreateorderController extends Zend_Controller_Action
{
public function testAction()
{
//more code
$users_obj = new Default_Model_Users(); //this would load the model using the Default namespace
//more code
}
}
My Defaul_Model_Users class would look something like this:
<?php
/**
* application/models/Users.php
*/
class Default_Model_Users extends Zend_Db_Table
{
protected $_table;
public function getTable()
{
if(null === $this->_table) {
$this->_table = new Default_Model_DbTable_Users();
}
return $this->_table;
}
public function fetchAll()
{
$result = $this->getTable()->fetchAll();
return $result;
}
}
And the part of the model which "interacts" directly with the database tables is found inside DbTable directory will look like this:
<?php
/**
* application/models/DbTable/Users.php
*/
class Default_Model_DbTable_Users extends Zend_Db_Table_Abstract
{
/** Table name */
protected $_name = 'users';
public function init()
{
$this->_db->setFetchMode(Zend_Db::FETCH_OBJ);
}
}
Then I would have the same application.ini generated by Zend Framework with this small addition:
resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.dbname = "mydb"
resources.db.params.username = "root"
resources.db.params.password = "password"
That is how I did without without having to change the bootstrap files.
I didn't want to use the registry to store an object that I should be able to access, so I did a little digging. It turns out that the bootstrap is registered as the front controller parameter "bootstrap", which is accessible from any of your controllers as explained in this manual page for Zend_Application.
So in your controller classes you can get the db adapter that has been defined in your ini file like this:
$bootstrap = $this->getInvokeArg('bootstrap');
$resource = $bootstrap->getPluginResource('db');
$db = $resource->getDbAdapter();