How to store and change Zend_Auth session ID? - php

I've recently started using Zend Framework and I'm still pretty used to session_start, and assigning variables to certain session names (ie: $_SESSION['username'] == $username)
I'm trying to figure out how to do something similar to this in Zend. Right now, my auth script checks the credentials using LDAP against my AD server and, if successful, authenticates the user.
I want to create a script that will allow an admin user to easily "enter" someone else's session. Let's say admin1 had an active session and wanted to switch into user1's session. Normally I would just change the $_SESSION['username'] variable and effectively change the identity of the user logged in.
But with Zend, I'm not quite sure how to change the session info. For what it's worth, here's my authentication script:
class LoginController extends Zend_Controller_Action
{
public function getForm()
{
return new LoginForm(array(
'action' => '/login/process',
'method' => 'post',
));
}
public function getAuthAdapter(array $params)
{
$username = $params['username'];
$password = $params['password'];
$auth = Zend_Auth::getInstance();
require_once 'Zend/Config/Ini.php';
$config = new Zend_Config_Ini('../application/configs/application.ini', 'production');
$log_path = $config->ldap->log_path;
$options = $config->ldap->toArray();
unset($options['log_path']);
require_once 'Zend/Auth/Adapter/Ldap.php';
$adapter = new Zend_Auth_Adapter_Ldap($options, $username, $password);
$result = $auth->authenticate($adapter);
if ($log_path) {
$messages = $result->getMessages();
require_once 'Zend/Log.php';
require_once 'Zend/Log/Writer/Stream.php';
require_once 'Zend/Log/Filter/Priority.php';
$logger = new Zend_Log();
$logger->addWriter(new Zend_Log_Writer_Stream($log_path));
$filter = new Zend_Log_Filter_Priority(Zend_Log::DEBUG);
$logger->addFilter($filter);
foreach ($messages as $i => $message) {
if ($i-- > 1) { // $messages[2] and up are log messages
$message = str_replace("\n", "\n ", $message);
$logger->log("Ldap: $i: $message", Zend_Log::DEBUG);
}
}
}
return $adapter;
}
public function preDispatch()
{
if (Zend_Auth::getInstance()->hasIdentity()) {
// If the user is logged in, we don't want to show the login form;
// however, the logout action should still be available
if ('logout' != $this->getRequest()->getActionName()) {
$this->_helper->redirector('index', 'index');
}
} else {
// If they aren't, they can't logout, so that action should
// redirect to the login form
if ('logout' == $this->getRequest()->getActionName()) {
$this->_helper->redirector('index');
}
}
}
public function indexAction()
{
$this->view->form = $this->getForm();
}
public function processAction()
{
$request = $this->getRequest();
// Check if we have a POST request
if (!$request->isPost()) {
return $this->_helper->redirector('index');
}
// Get our form and validate it
$form = $this->getForm();
if (!$form->isValid($request->getPost())) {
// Invalid entries
$this->view->form = $form;
return $this->render('index'); // re-render the login form
}
// Get our authentication adapter and check credentials
$adapter = $this->getAuthAdapter($form->getValues());
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($adapter);
if (!$result->isValid()) {
// Invalid credentials
$form->setDescription('Invalid credentials provided');
$this->view->form = $form;
return $this->render('index'); // re-render the login form
}
// We're authenticated! Redirect to the home page
$this->_helper->redirector('index', 'index');
}
public function logoutAction()
{
Zend_Auth::getInstance()->clearIdentity();
$this->_helper->redirector('index'); // back to login page
}
}
Is there any way to do what I have described? Thanks for any suggestions.

Given your code, the result of authenticating is stored in the PHP session through a Zend_Auth_Storage_Session object.
Calling Zend_Auth::getIdentity() gets access to the storage and returns the result if it is not empty. Likewise, you can change the stored identity by getting access to the underlying storage and changing its value. The actual identity stored as a result of authenticating with Zend_Auth_Adapter_Ldap is just a string value representing the LDAP username.
To effectively change the logged in user, you can do:
Zend_Auth::getInstance()->getStorage()->write('newUserName');
This assumes the default behavior which should be in place given your code.
What I do in my applications after successful authentication is to create a new object of some User model, and write that to the Zend_Auth session so that I have more information about the user available in each session, so you should be aware that different things can be in the storage depending on the application.
This is what I do for example:
$auth = new Zend_Auth(...);
$authResult = $auth->authenticate();
if ($authResult->isValid() == true) {
$userobj = new Application_Model_UserSession();
// populate $userobj with much information about the user
$auth->getStorage()->write($userobj);
}
Now anywhere in my application I call Zend_Auth::getInstance()->getIdentity() I get back the Application_Model_UserSession object rather than a string; but I digress.
The information that should help you is:
$user = Zend_Auth::getInstance()->getIdentity(); // reads from auth->getStorage()
Zend_Auth::getInstance()->getStorage()->write($newUser);

Related

How to log expiration time when a user session expired in Zend Auth

I want to add user logins and logout/session expiration info into database, Its easy for normal login and logout, but I couldn’t figure out how to proceed with automatic session expirations.
My authentication works like below.
My Login controller action
if ($request->isPost()) {
$data = $request->getParams();
$userModel = new Application_Model_User_DbTable();
if ($user = $userModel->login($data['email'], $data['password'])) {
/* check if user is activated or not */
if ($user['status'] == 0) {
$this->view->loginerror = "<b>Account not active :</b> Please wait for admin to activate your account";
}elseif($user['status'] == -1){
$this->view->loginerror = "<b>Account Suspended :</b> Your account is suspeneded you must contact admin to continue";
}else {
/* Store authentication data in session */
$auth = Zend_Auth::getInstance();
$identity = Zend_Auth::getInstance()->getStorage();
$identity->write($user);
$this->_redirect('/fax');
}
} else {
$this->view->loginerror = "<b>Invalid login :</b> Email or passsword is invalid !";
}
}
Authenticate Method in my user control
function authenticate($email, $password) {
$where = array();
$where[] = $this->getAdapter()->quoteinto('email = ?', $email);
$user = $this->fetchRow($where);
if (isset($user['email'])) {
$salt = $user['password_salt'];
if (sha1($password . $salt) == $user['password']) {
/** here i will add login session info**/
return $user;
}
return false;
}
return false;
}
I am afraid that there is no core PHP or Zend function to perform this, session timeout doesn't run in the background. Unless timed out session makes another request, it is not even possible to know if session is timed out.
One of the method would be to make ajax request to a action to check for time outs and update your db in that action.

Get security token for non-logged user with Symfony

How can I get a security token for any user, not only the one currently logged in ?
I would like to be able to call isGranted() on a user fetched from the database
isGranted() comes from the Security service, so it would be hard/unnecessary to use that to get Roles without adjusting the state of the session.
Don't get me wrong, it's definitely possible... This would work, for example:
public function strangeAction()
{
// Get your User, however you normally get it
$user = $userRepository->find($id);
// Save the current token so you can put it back later
$previousToken = $this->get("security.context")->getToken();
// Create a new token
$token = new UsernamePasswordToken($user, null, "main", $user->getRoles());
// Update the security context with the new token
$this->get("security.context")->setToken($token);
// Now you have access to isGranted()
if ($this->get("security.context")->isGranted("ROLE_SOMETHING"))
{ /* Do something here */ }
// Don't forget to reset the token!
$this->get("security.context")->setToken($previousToken);
}
...but that really makes no sense.
In reality, you don't need the token. A much better way of doing this would be to add an isGranted() method into your User entity:
// Namespace\YourBundle\Entity\User.php
class User
{
...
public function isGranted($role)
{
return in_array($role, $this->getRoles());
}
...
}
Now you can get those roles in your controllers:
public function notSoStrangeAction()
{
// Get your User, however you normally get it
$user = $userRepository->find($id);
// Find out if that User has a Role associated to it
if ($user->isGranted("ROLE_SOMETHING"))
{ /* Do something here */ }
}
I had the same requirements a while ago. So I implemented it myself. Since you require the hierarchy information from the container it is not possible advised to extend the user entity with this functionality though.
// first check if the role is inside the user roles of the user
// if not then check for each user role if it is a master role of the check role
public function isGranted($user, $checkrole){
$userroles = $user->getRoles();
if (in_array($checkrole, $userroles)){return true;}
foreach ($userroles as $userrole){
if ($this->roleOwnsRole($userrole, $checkrole)){return true;}
}
return false;
}
// recursively loop over the subroles of the master to check if any of them are
// the suggested slave role. If yes then the masterrole is a master and has
// the same grants as the slave.
private function roleOwnsRole($masterRole, $slaveRole, $checkvalidityroles=true, $hierarchy=null)
{
if ($hierarchy===null){$hierarchy = $this->container->getParameter('security.role_hierarchy.roles');}
if ($masterRole === $slaveRole){ return false; }
if($checkvalidityroles && (!array_key_exists($masterRole, $hierarchy) || !array_key_exists($slaveRole, $hierarchy))){ return false; }
$masterroles = $hierarchy[$masterRole];
if(in_array($slaveRole, $masterroles)){
return true;
}else{
foreach($masterroles as $masterrolerec){
if ($this->roleOwnsRole($masterrolerec, $slaveRole, false, $hierarchy)){return true;}
}
return false;
}
}
I think the best way is to call AccessDecisionManager manually - like $securityContext->isGranted() does as well but for the currently logged in user. This is good too if you are using Symfony Voters to determine access.
$token = new UsernamePasswordToken($userObject, 'none', 'main', $userObject->getRoles());
$hasAccess = $this->get('security.access.decision_manager')->decide($token, array('voter'), $optionalObjectToCheckAccessTo);

How to save values in session?

I am working with cakephp.Recently I am facing problem in saving data in session.
I have created login page which will send value to controller/action. it will receives like this.
function ajaxCall() {
$this->autoRender = false;
$this->layout = 'ajax';
$arrData = $this->params['url'];
if(!empty($arrData)){
if($arrData['submit']=='Y'){
$userObj = new Api(); // create an instance of the user class
$userInfo = $userObj->login($arrData['email'],$arrData['password']); // call the api login user methods
$xml = simplexml_load_string($userInfo);
$userId = $xml->message->id;
if($userId != "0" && $userId != ""){
$this->setCurrentUserId($userId);
echo "success";
}
else{
echo "no";
}
}
}
}
public function setCurrentUserId($userId)
{
//Is session alive
//if not then redirect to session time out page
//session_start();
//session_register("");
if($userId == 419 || $userId == 423){
$userId1 = $this->Session->write('userId', $userId);
}else{
$userId1 = $this->Session->write('userId', $userId);
}
return $userId1;
}
my controller contain also these line to include helpers,component
public $components = array('Session');
public $helpers = array('Html','Session');
and in core.php file i set session as-
Configure::write('Session', array(
'defaults' => 'php', 'ini' => array('session.auto_start' => 1)
));
Please help me as i am unable to save userId in session
Thanks
On the internet there You can find CakePHP cookbook to create simple application with authentication and authorization: book.cakephp.org
Here You can find very simple example on how to create UsersController, User model and Views for login etc with login action using CakePHP's inbuilt Auth object - there is no need to write the whole login logic - Auth object will do most for You.
Hope You'll enjoy it!

How to set the timeout while using Zend_auth in Zend framework

I am using Zend_auth for authentication purposes.Code for the same is as follows:
$authAdapter = $this->getAuthAdapter();
$authAdapter->setIdentity($username)
->setCredential($password);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
# is the user a valid one?
if ($result->isValid()) {
# all info about this user from the login table
# ommit only the password, we don't need that
$userInfo = $authAdapter->getResultRowObject(null, 'password');
# the default storage is a session with namespace Zend_Auth
$authStorage = $auth->getStorage();
$authStorage->write($userInfo);
$emp_id = $userInfo->employee_id;
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$array_db = new Application_Model_SetMstDb();
$array_name = $array_db->getName($emp_id);
foreach ($array_name as $name) :
$fname = $name['first_name'];
$lname = $name['last_name'];
endforeach;
$firstname = new stdClass;
$lastname = new stdClass;
$userInfo->firstname = $fname;
$userInfo->lastname = $lname;
$privilege_id = $userInfo->privilege_id;
echo 'privilege in Login: ' . $privilege_id;
$this->_redirect('index/index');
} else {
$errorMessage = "Invalid username or password";
$this->view->error = $errorMessage;
}
where getAuthAdapter() as follows:
protected function getAuthAdapter() {
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
$authAdapter->setTableName('credentials')
->setIdentityColumn('employee_id')
->setCredentialColumn('password');
return $authAdapter;
}
I want to set a session timeout.I want to set a timeout of 5 mins and when user does not being active for 5 mins then session should be expired that is logout action should be called whose code is as follows:
public function logoutAction() {
// action body
Zend_Auth::getInstance()->clearIdentity();
$this->_redirect('login/index');
}
Thanks in advance.Plz Help me.Its urgent.
When I use
$session = new Zend_Session_Namespace( 'Zend_Auth' );
$session->setExpirationSeconds( 60 );
control redirects to login page automatically after 60 seconds but I want that if the user of the application in inactive for 60 seconds then only it redirects.At present whether user is active or not redirection occurs.
I wouldn't use init() for this. init() should be use to set object state.
I would use preDispatch(). But to avoid using it all controllers or making a base controller and then extending. You could do a plugin and add it on the Bootstrap.
class YourControllerPlugin extends Zend_Controller_Plugin_Abstract {
public function preDispatch() {
//check if expired
if(hasExpired()) {
//logout and redirect
}
}
}
to add it on Bootstrap :
public function __initYourPlugin () {
$this->bootstrap('frontController');
$plugin = new YourControllerPlugin();
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin($plugin);
return $plugin;
}
I'm looking at my code for this right now. This snippet is from a front controller plugin. Each time an authenticated user requests a page, I reset their session expiration so they've got 60mins from they were last "active".
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request) {
//check whether the client is authenticated
if (Zend_Auth::getInstance()->hasIdentity()) {
$session = $this->_getAuthSession();
//update session expiry date to 60mins from NOW
$session->setExpirationSeconds(60*60);
return;
}
Aside: I'm looking over this code for a way to show the user a "your session has expired" message rather than the current "you're not authenticated" message.

Show login form on every page using Zend Form

I cant seem to figure out how to create a flexible sidebar containing and login form (Zend_Form) and various module/controller specific links.
The most common solution seems to be using:
echo $this->action('login', 'authentication', 'default');
But apperently this isnt the 'best' way? I've read that this apprently triggers a dispatchloop and thereby take a performance hit?
I've thought about sing a View_Helper for the sidebar:
class Zend_View_Helper_Sidebar extends Zend_View_Helper_Abstract
{
public function sidebar()
{
$sidebar = $this->view->placeholder('sidebar');
$sidebar->setPrefix('<div class="sidebar-element">')
->setSeparator('</div><div class="sidebar-element">')
->setPostfix('</div>');
$sidebar->append(new Form_Login);
$sidebar->append(new Model_Category->getList());
return $sidebar
}
}
In my Form_Login i have action set to /auth/login which contains the following code:
public function loginAction()
{
$request = $this->getRequest();
if($request->isPost()) {
$form = new Form_Login();
$data = $request->getPost();
if($form->isValid($data)) {
$username = $form->getValue('username');
$password = $form->getValue('password');
$users = new Model_DbTable_Users();
$authenticated = $users->login($username, $password);
if($authenticated) {
//Succes - show identity instead of loginForm
} else {
$this->view->loginForm = $form;
$this->render('/index');
}
}
}
}
If I provide the wrong username/password it renders indexAction which is currently empty. This is fine. It also renders my sidebar containing the loginForm as needed, but the form is empty (The user input is not displayed. Neither is no message that the form failed to validate).
The username-field in the form should display the input that the user provided before submitting. And a error message should be displayed.
Any help as to why this is not happing, is very much appriciated.
You are doing your form validation in a loginAction and you said you are currently posting to index action, is that a typo?
Besides that, you are creating two copies of the Form_Login. Once, in the action and once in view helper. If you validate on one instance in the action, you need to display that same instance of the form in the view helper. You could either move all the validation logic into the view helper or you could share the instance between the view helper and the action. I'm going to suggest the latter.
Check in your view helper if a form already exists in the registry. If it does, just use that instance. Otherwise you can create a new instance. Here's a rough example of what I mean:
class Zend_View_Helper_Sidebar extends Zend_View_Helper_Abstract
{
public function sidebar()
{
$sidebar = $this->view->placeholder('sidebar');
$sidebar->setPrefix('<div class="sidebar-element">')
->setSeparator('</div><div class="sidebar-element">')
->setPostfix('</div>');
if(Zend_Registry::isReigistered('loginForm')) {
$loginForm = Zend_Registry::get('loginForm');
} else {
$loginForm = new Form_Login();
}
$sidebar->append($loginForm);
$sidebar->append(new Model_Category->getList());
return $sidebar
}
}
public function loginAction()
{
$form = new Form_Login();
Zend_Registry::set('loginForm', $form);
$request = $this->getRequest();
if($request->isPost()) {
$data = $request->getPost();
if($form->isValid($data)) {
$username = $form->getValue('username');
$password = $form->getValue('password');
$users = new Model_DbTable_Users();
$authenticated = $users->login($username, $password);
if($authenticated) {
//Succes - show identity instead of loginForm
} else {
$this->view->loginForm = $form;
$this->render('/index');
}
}
}
}
Edit:
No, there is no self checking if an instance of a form already exists. You must do this yourself.
I'm pretty sure the suggested way is to use a view helper. As you said in your question, using the action view helper causes another dispatch loop which is bad for performance. I don't know what the verdict is on whether all logic should be kept in the view helper or not.

Categories