14

See the following scenario.
I have some custom module that allows the frontend user to perform some actions on some custom entities. (details are not really important).
The request is that an admin should be able to login on the frontend with the customer account (without having the password) and be able to perform those actions for the customer.
Since you cannot use the the frontend session from the backend and I don't want to create a permanent autologin link for frontend since is might be a big security hole this is what I did so far.

  • add an empty attribute for the customer entity. (let's call it login_key)
  • add a button in the backend on the customer edit page that redirects to an admin page where a random string is generated and saved in the attribute login_key.
  • in the same action I redirect the admin to a frontend url like this autologin/index/index/customer_id/7/login_key/ajkshdkjah123123 (value generated in previous step).
  • at the frontend url, if the customer id and login_key match for a specific customer then I set the customer object in session (as logged in) and delete the login_key so the url won't work in the future.

This seams to work. I mean, I get logged in as the selected customer and the link used for autologin does not work a second time.
The down side is that if 2 admins click on the "autologin" button around the same time, one will fail to login, but this is an acceptable risk.
My main concern is that this may also be a (not that) big security issue. Can someone see something wrong with this approach? or suggest a better one?
Ignore the fact that the customer accounts can be separated by website. This is not important and also can be managed easily.

  • Wouldn't regular admin URL keys give you just as much security? – kalenjordan Oct 31 '13 at 13:23
  • @kalenjordan The problem is not the admin part. That seams OK. My concern is when calling the frontend URL for autologin. I cannot use admin URL keys in there. – Marius Oct 31 '13 at 13:27
  • Ah right, sorry. Have you checked out magentocommerce.com/magento-connect/login-as-customer-9893.html ? It generates a unique record per login attempt by the admin, with a unique hash associated to the customer ID which is used in the frontend controller. – kalenjordan Oct 31 '13 at 13:47
  • @kalenjordan Ha Ha. I didn't know about that extension. but from what you described is the same approach I described in the question. :). I will take a look at it. Thanks. – Marius Oct 31 '13 at 13:52
  • 1
    @mageUz.True, but like I said, that's an acceptable risk. I'm more concerned with security here. – Marius Oct 31 '13 at 20:38
9

Since no one came up with a good reason not to do what I was asking I assume that my method is kind of safe. So, in order not to leave this question open, I decided to add the code as an answer and mark it as accepted.
So I have a new extension called Easylife_Simulate with the following files: app/etc/modules/Easylife_Simulte.xml - the declaration file:

<?xml version="1.0"?>
<config>
    <modules>
        <Easylife_Simulate>
            <codePool>local</codePool>
            <active>true</active>
            <depends>
                <Mage_Customer />
            </depends>
        </Easylife_Simulate>
    </modules>
</config>

app/code/local/Easylife/Simulte/etc/config.xml - the configuration file

<?xml version="1.0"?>
<config>
    <modules>
        <Easylife_Simulate>
            <version>0.0.1</version>
        </Easylife_Simulate>
    </modules>
    <global>
        <helpers>
            <easylife_simulate>
                <class>Easylife_Simulate_Helper</class>
            </easylife_simulate>
        </helpers>
        <models>
            <easylife_simulate>
                <class>Easylife_Simulate_Model</class>
            </easylife_simulate>
        </models>
        <resources>
            <easylife_simulate_setup>
                <setup>
                    <module>Easylife_Simulate</module>
                    <class>Mage_Customer_Model_Resource_Setup</class>
                </setup>
            </easylife_simulate_setup>
        </resources>
    </global>
    <frontend>
        <routers>
            <easylife_simulate>
                <use>standard</use>
                <args>
                    <module>Easylife_Simulate</module>
                    <frontName>simulate</frontName>
                </args>
            </easylife_simulate>
        </routers>
    </frontend>
    <adminhtml>
        <events>
            <controller_action_layout_render_before_adminhtml_customer_edit>
                <observers>
                    <easylife_simulate>
                        <class>easylife_simulate/observer</class>
                        <method>addAutoLoginButton</method>
                    </easylife_simulate>
                </observers>
            </controller_action_layout_render_before_adminhtml_customer_edit>
        </events>
    </adminhtml>
    <admin>
        <routers>
            <adminhtml>
                <args>
                    <modules>
                        <Easylife_Simulate before="Mage_Adminhtml">Easylife_Simulate_Adminhtml</Easylife_Simulate>
                    </modules>
                </args>
            </adminhtml>
        </routers>
    </admin>
</config>

app/code/local/Easylife/Simulate/sql/easylife_simulate_setup/install-0.0.1.php - install script - adds a new customer attribute:

<?php
$this->addAttribute('customer', 'login_key', array(
    'type'      => 'text',
    'label'     => 'Auto login key',
    'input'     => 'text',
    'position'  => 999,
    'required'  => false
));

app/code/local/Easylife/Simulate/Model/Observer.php - observer to add a button in the customer admin edit form

<?php
class Easylife_Simulate_Model_Observer extends Mage_ProductAlert_Model_Observer{
    public function addAutoLoginButton($observer){
        $block = Mage::app()->getLayout()->getBlock('customer_edit');
        if ($block){
            $customer = Mage::registry('current_customer');
            $block->addButton('login', array(
                'label'     => Mage::helper('customer')->__('Login as this customer'),
                'onclick'   => 'window.open(\''.Mage::helper('adminhtml')->getUrl('adminhtml/simulate/login', array('id'=>$customer->getId())).'\')',
            ), 100);
        }

    }
}

app/code/local/Easylife/Simulate/controllers/Adminhtml/SimulateController.php - the admin controller that handles the click on the button generated above.

<?php
class Easylife_Simulate_Adminhtml_SimulateController extends Mage_Adminhtml_Controller_Action{
    public function loginAction(){
        $id = $this->getRequest()->getParam('id');
        $customer = Mage::getModel('customer/customer')->load($id);
        if (!$customer->getId()){
            Mage::getSingleton('adminhtml/session')->addError(Mage::helper('easylife_simulate')->__('Customer does not exist'));
            $this->_redirectReferer();
        }
        else {
            $key = Mage::helper('core')->uniqHash();
            $customer->setLoginKey($key)->save();
            $this->_redirect('simulate/index/index', array('id'=>$customer->getId(), 'login_key'=>$key));
        }
    }
}

app/code/local/Easylife/Simulate/controllers/IndexController.php - the frontend controller that makes the autologin.

<?php
class Easylife_Simulate_IndexController extends Mage_Core_Controller_Front_Action{
    public function indexAction(){
        $id = $this->getRequest()->getParam('id');
        $key = $this->getRequest()->getParam('login_key');
        if (empty($key)){
            $this->_redirect('');
        }
        else{
            $customer = Mage::getModel('customer/customer')->load($id);
            if ($customer->getId() && $customer->getLoginKey() == $key){
                $customer->setLoginKey('')->save();
                Mage::getSingleton('customer/session')->setCustomerAsLoggedIn($customer);
                Mage::getSingleton('customer/session')->renewSession();
            }
            $this->_redirect('customer/account/index');
        }
    }
}

app/code/local/Easylife/Simulte/Helper/Data.php - the module helper

<?php
class Easylife_Simulate_Helper_Data extends Mage_Core_Helper_Abstract{

}

That's it. It seams to work for me. Like I said in the question, the downside is that if 2 admins press the login button for the same customer at (approximately) the same time, one of them will not be logged in. But he can repeat the process a few seconds later.

  • What happen when there is multiple customer ? – Milople Inc Jan 27 '14 at 4:33
  • @GarthHuff I don't understand your question. Please describe your scenario. – Marius Jan 27 '14 at 6:19
  • i think, i have change whole scenario what i have done is Replace the user name input box with drop-down with possible user name and login automatically when user name selected from dropdown. This is my implmentation techworkslab.pixub.com/2014/01/script-for-auto-login – Milople Inc Jan 27 '14 at 7:56
  • @GarthHuff. Thanks for the script, but my problem is related to frontend customers, not admins. – Marius Jan 27 '14 at 7:59
  • @Marius do you plan on making a Magento 2 version of this? – Dan May 1 '17 at 14:03
0

We use a similar approach for our customer service team called "ghost login" where we make a button available via customer account in admin. We are not using any custom attributes for login_key or anything like that and are actually using an overridden/customized loginAction extended from Mage_Customer_AccountController to process the login.

Additionally, during loginAction, after our custom logic and validation, we are using Mage_Customer_Model_Session::setCustomerAsLoggedIn to ensure that we are not losing out on any event functionality that may be executed during login. If you take a look at this method you will notice that it sets the customer in the session as well as dispatches the customer_login event.

enter image description here

With this approach we can actually have multiple agents log in as the same customer should we choose (although we wouldn't want to have multiple agents adding to cart/placing orders at the same time on the same account).

We have been using this for two years now with no notable issues during that time.

  • 1
    Thanks for the info. I also use setCustomerAsLoggedIn in my code, for the same reason as you do. But I was curious of the method to use for autologin. (if it's not a secret). – Marius Oct 31 '13 at 14:05
  • We have built a custom module to handle this that extends from the core frontend login functionality. – Anthony Leach Jr Oct 31 '13 at 14:08
  • I got that. I was asking about some code, if possible, or at least the idea behind the code. Or maybe some pointers if my idea is safe or not. – Marius Oct 31 '13 at 14:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.