Source for file joomla.php

Documentation is available at joomla.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Plugin
  4.  * @subpackage  User.joomla
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE.txt
  8.  */
  9.  
  10. defined('_JEXEC'or die;
  11.  
  12. /**
  13.  * Joomla User plugin
  14.  *
  15.  * @package     Joomla.Plugin
  16.  * @subpackage  User.joomla
  17.  * @since       1.5
  18.  */
  19. class PlgUserJoomla extends JPlugin
  20. {
  21.     /**
  22.      * Application object
  23.      *
  24.      * @var    JApplicationCms 
  25.      * @since  3.2
  26.      */
  27.     protected $app;
  28.  
  29.     /**
  30.      * Database object
  31.      *
  32.      * @var    JDatabaseDriver 
  33.      * @since  3.2
  34.      */
  35.     protected $db;
  36.  
  37.     /**
  38.      * True to use strong password encryption
  39.      *
  40.      * @var    boolean 
  41.      * @since  3.2
  42.      */
  43.     protected $useStrongEncryption;
  44.  
  45.     /**
  46.      * Constructor. We use it to set the app and db properties.
  47.      *
  48.      * @param   object  &$subject  The object to observe
  49.      * @param   array   $config    An optional associative array of configuration settings.
  50.      *                              Recognized key values include 'name', 'group', 'params', 'language'
  51.      *                              (this list is not meant to be comprehensive).
  52.      *
  53.      * @since   3.2
  54.      */
  55.     public function __construct(&$subject$config array())
  56.     {
  57.         parent::__construct($subject$config);
  58.  
  59.         // As of CMS 3.2 strong encryption is the default.
  60.         $this->useStrongEncryption = $this->params->get('strong_passwords'true);
  61.     }
  62.  
  63.     /**
  64.      * Remove all sessions for the user name
  65.      *
  66.      * Method is called after user data is deleted from the database
  67.      *
  68.      * @param   array    $user     Holds the user data
  69.      * @param   boolean  $success  True if user was succesfully stored in the database
  70.      * @param   string   $msg      Message
  71.      *
  72.      * @return  boolean 
  73.      *
  74.      * @since   1.6
  75.      */
  76.     public function onUserAfterDelete($user$success$msg)
  77.     {
  78.         if (!$success)
  79.         {
  80.             return false;
  81.         }
  82.  
  83.         $this->db->getQuery(true)
  84.             ->delete($this->db->quoteName('#__session'))
  85.             ->where($this->db->quoteName('userid'' = ' . (int) $user['id'])
  86.             ->execute();
  87.  
  88.         return true;
  89.     }
  90.  
  91.     /**
  92.      * Utility method to act on a user after it has been saved.
  93.      *
  94.      * This method sends a registration email to new users created in the backend.
  95.      *
  96.      * @param   array    $user     Holds the new user data.
  97.      * @param   boolean  $isnew    True if a new user is stored.
  98.      * @param   boolean  $success  True if user was succesfully stored in the database.
  99.      * @param   string   $msg      Message.
  100.      *
  101.      * @return  void 
  102.      *
  103.      * @since   1.6
  104.      */
  105.     public function onUserAfterSave($user$isnew$success$msg)
  106.     {
  107.         $mail_to_user $this->params->get('mail_to_user'1);
  108.  
  109.         if ($isnew)
  110.         {
  111.             // TODO: Suck in the frontend registration emails here as well. Job for a rainy day.
  112.             if ($this->app->isAdmin())
  113.             {
  114.                 if ($mail_to_user)
  115.                 {
  116.                     // Load user_joomla plugin language (not done automatically).
  117.                     $lang JFactory::getLanguage();
  118.                     $lang->load('plg_user_joomla'JPATH_ADMINISTRATOR);
  119.  
  120.                     // Compute the mail subject.
  121.                     $emailSubject JText::sprintf(
  122.                         'PLG_USER_JOOMLA_NEW_USER_EMAIL_SUBJECT',
  123.                         $user['name'],
  124.                         $config $this->app->get('sitename')
  125.                     );
  126.  
  127.                     // Compute the mail body.
  128.                     $emailBody JText::sprintf(
  129.                         'PLG_USER_JOOMLA_NEW_USER_EMAIL_BODY',
  130.                         $user['name'],
  131.                         $this->app->get('sitename'),
  132.                         JUri::root(),
  133.                         $user['username'],
  134.                         $user['password_clear']
  135.                     );
  136.  
  137.                     // Assemble the email data...the sexy way!
  138.                     $mail JFactory::getMailer()
  139.                         ->setSender(
  140.                             array(
  141.                                 $this->app->get('mailfrom'),
  142.                                 $this->app->get('fromname')
  143.                             )
  144.                         )
  145.                         ->addRecipient($user['email'])
  146.                         ->setSubject($emailSubject)
  147.                         ->setBody($emailBody);
  148.  
  149.                     if (!$mail->Send())
  150.                     {
  151.                         $this->app->enqueueMessage(JText::_('ERROR_SENDING_EMAIL')'warning');
  152.                     }
  153.                 }
  154.             }
  155.         }
  156.         else
  157.         {
  158.             // Existing user - nothing to do...yet.
  159.         }
  160.     }
  161.  
  162.     /**
  163.      * This method should handle any login logic and report back to the subject
  164.      *
  165.      * @param   array  $user     Holds the user data
  166.      * @param   array  $options  Array holding options (remember, autoregister, group)
  167.      *
  168.      * @return  boolean  True on success
  169.      *
  170.      * @since   1.5
  171.      */
  172.     public function onUserLogin($user$options array())
  173.     {
  174.         $instance $this->_getUser($user$options);
  175.  
  176.         // If _getUser returned an error, then pass it back.
  177.         if ($instance instanceof Exception)
  178.         {
  179.             return false;
  180.         }
  181.  
  182.         // If the user is blocked, redirect with an error
  183.         if ($instance->get('block'== 1)
  184.         {
  185.             $this->app->enqueueMessage(JText::_('JERROR_NOLOGIN_BLOCKED')'warning');
  186.  
  187.             return false;
  188.         }
  189.  
  190.         // Authorise the user based on the group information
  191.         if (!isset($options['group']))
  192.         {
  193.             $options['group''USERS';
  194.         }
  195.  
  196.         // Check the user can login.
  197.         $result $instance->authorise($options['action']);
  198.  
  199.         if (!$result)
  200.         {
  201.             $this->app->enqueueMessage(JText::_('JERROR_LOGIN_DENIED')'warning');
  202.  
  203.             return false;
  204.         }
  205.  
  206.         // Mark the user as logged in
  207.         $instance->set('guest'0);
  208.  
  209.         // If the user has an outdated hash, update it.
  210.         if (substr($user['password']04!= '$2y$' && $this->useStrongEncryption && JCrypt::hasStrongPasswordSupport(== true)
  211.         {
  212.             if (strlen($user['password']55)
  213.             {
  214.                 $user['password'substr($user['password']055);
  215.  
  216.                 JFactory::getApplication()->enqueueMessage(JText::_('JLIB_USER_ERROR_PASSWORD_TRUNCATED')'notice');
  217.             }
  218.  
  219.             $instance->password password_hash($user['password']PASSWORD_BCRYPT);
  220.             $instance->save();
  221.         }
  222.  
  223.         // Register the needed session variables
  224.         $session JFactory::getSession();
  225.         $session->set('user'$instance);
  226.  
  227.         // Check to see the the session already exists.
  228.         $this->app->checkSession();
  229.  
  230.         // Update the user related fields for the Joomla sessions table.
  231.         $query $this->db->getQuery(true)
  232.             ->update($this->db->quoteName('#__session'))
  233.             ->set($this->db->quoteName('guest'' = ' $this->db->quote($instance->guest))
  234.             ->set($this->db->quoteName('username'' = ' $this->db->quote($instance->username))
  235.             ->set($this->db->quoteName('userid'' = ' . (int) $instance->id)
  236.             ->where($this->db->quoteName('session_id'' = ' $this->db->quote($session->getId()));
  237.         $this->db->setQuery($query)->execute();
  238.  
  239.         // Hit the user last visit field
  240.         $instance->setLastVisit();
  241.  
  242.         return true;
  243.     }
  244.  
  245.     /**
  246.      * This method should handle any logout logic and report back to the subject
  247.      *
  248.      * @param   array  $user     Holds the user data.
  249.      * @param   array  $options  Array holding options (client, ...).
  250.      *
  251.      * @return  object  True on success
  252.      *
  253.      * @since   1.5
  254.      */
  255.     public function onUserLogout($user$options array())
  256.     {
  257.         $my      JFactory::getUser();
  258.         $session JFactory::getSession();
  259.  
  260.         // Make sure we're a valid user first
  261.         if ($user['id'== && !$my->get('tmp_user'))
  262.         {
  263.             return true;
  264.         }
  265.  
  266.         // Check to see if we're deleting the current session
  267.         if ($my->get('id'== $user['id'&& $options['clientid'== $this->app->getClientId())
  268.         {
  269.             // Hit the user last visit field
  270.             $my->setLastVisit();
  271.  
  272.             // Destroy the php session for this user
  273.             $session->destroy();
  274.         }
  275.  
  276.         // Force logout all users with that userid
  277.         $query $this->db->getQuery(true)
  278.             ->delete($this->db->quoteName('#__session'))
  279.             ->where($this->db->quoteName('userid'' = ' . (int) $user['id'])
  280.             ->where($this->db->quoteName('client_id'' = ' . (int) $options['clientid']);
  281.         $this->db->setQuery($query)->execute();
  282.  
  283.         return true;
  284.     }
  285.  
  286.     /**
  287.      * This method will return a user object
  288.      *
  289.      * If options['autoregister'] is true, if the user doesn't exist yet he will be created
  290.      *
  291.      * @param   array  $user     Holds the user data.
  292.      * @param   array  $options  Array holding options (remember, autoregister, group).
  293.      *
  294.      * @return  object  JUser object
  295.      *
  296.      * @since   1.5
  297.      */
  298.     protected function _getUser($user$options array())
  299.     {
  300.         $instance JUser::getInstance();
  301.         $id = (int) JUserHelper::getUserId($user['username']);
  302.  
  303.         if ($id)
  304.         {
  305.             $instance->load($id);
  306.  
  307.             return $instance;
  308.         }
  309.  
  310.         // TODO : move this out of the plugin
  311.         $config JComponentHelper::getParams('com_users');
  312.  
  313.         // Hard coded default to match the default value from com_users.
  314.         $defaultUserGroup $config->get('new_usertype'2);
  315.  
  316.         $instance->set('id'0);
  317.         $instance->set('name'$user['fullname']);
  318.         $instance->set('username'$user['username']);
  319.         $instance->set('password_clear'$user['password_clear']);
  320.  
  321.         // Result should contain an email (check).
  322.         $instance->set('email'$user['email']);
  323.         $instance->set('groups'array($defaultUserGroup));
  324.  
  325.         // If autoregister is set let's register the user
  326.         $autoregister = isset($options['autoregister']$options['autoregister'$this->params->get('autoregister'1);
  327.  
  328.         if ($autoregister)
  329.         {
  330.             if (!$instance->save())
  331.             {
  332.                 JLog::add('Error in autoregistration for user ' .  $user['username''.'JLog::WARNING'error');
  333.             }
  334.         }
  335.         else
  336.         {
  337.             // No existing user and autoregister off, this is a temporary user.
  338.             $instance->set('tmp_user'true);
  339.         }
  340.  
  341.         return $instance;
  342.     }
  343.  
  344.     /**
  345.      * We set the authentication cookie only after login is successfullly finished.
  346.      * We set a new cookie either for a user with no cookies or one
  347.      * where the user used a cookie to authenticate.
  348.      *
  349.      * @param   array  options  Array holding options
  350.      *
  351.      * @return  boolean  True on success
  352.      *
  353.      * @since   3.2
  354.      */
  355.     public function onUserAfterLogin($options)
  356.     {
  357.         // Currently this portion of the method only applies to Cookie based login.
  358.         if (!isset($options['responseType']|| ($options['responseType'!= 'Cookie' && empty($options['remember'])))
  359.         {
  360.             return true;
  361.         }
  362.  
  363.         // We get the parameter values differently for cookie and non-cookie logins.
  364.         $cookieLifetime    empty($options['lifetime']$this->app->rememberCookieLifetime $options['lifetime'];
  365.         $length            empty($options['length']$this->app->rememberCookieLength $options['length'];
  366.         $secure            empty($options['secure']$this->app->rememberCookieSecure $options['secure'];
  367.  
  368.         // We need the old data to match against the current database
  369.         $rememberArray JUserHelper::getRememberCookieData();
  370.  
  371.         $privateKey JUserHelper::genRandomPassword($length);
  372.  
  373.         // We are going to concatenate with . so we need to remove it from the strings.
  374.         $privateKey str_replace('.'''$privateKey);
  375.  
  376.         $cryptedKey JUserHelper::getCryptedPassword($privateKey'''bcrypt'false);
  377.  
  378.         $cookieName JUserHelper::getShortHashedUserAgent();
  379.  
  380.         // Create an identifier and make sure that it is unique.
  381.         $unique false;
  382.  
  383.         do
  384.         {
  385.             // Unique identifier for the device-user
  386.             $series JUserHelper::genRandomPassword(20);
  387.  
  388.             // We are going to concatenate with . so we need to remove it from the strings.
  389.             $series str_replace('.'''$series);
  390.  
  391.             $query $this->db->getQuery(true)
  392.                 ->select($this->db->quoteName('series'))
  393.                 ->from($this->db->quoteName('#__user_keys'))
  394.                 ->where($this->db->quoteName('series'' = ' $this->db->quote(base64_encode($series)));
  395.  
  396.             $results $this->db->setQuery($query)->loadResult();
  397.  
  398.             if (is_null($results))
  399.             {
  400.                 $unique true;
  401.             }
  402.         }
  403.         while ($unique === false);
  404.  
  405.         // If a user logs in with non cookie login and remember me checked we will
  406.         // delete any invalid entries so that he or she can use remember once again.
  407.         if ($options['responseType'!== 'Cookie')
  408.         {
  409.             $query $this->db->getQuery(true)
  410.                 ->delete('#__user_keys')
  411.                 ->where($this->db->quoteName('uastring'' = ' $this->db->quote($cookieName))
  412.                 ->where($this->db->quoteName('user_id'' = ' $this->db->quote($options['user']->username));
  413.  
  414.             $this->db->setQuery($query)->execute();
  415.         }
  416.  
  417.         $cookieValue $privateKey '.' $series '.' $cookieName;
  418.  
  419.         // Destroy the old cookie.
  420.         $this->app->input->cookie->set($cookieNamefalsetime(42000$this->app->get('cookie_path')$this->app->get('cookie_domain'));
  421.  
  422.         // And make a new one.
  423.         $this->app->input->cookie->set(
  424.             $cookieName$cookieValue$cookieLifetime$this->app->get('cookie_path')$this->app->get('cookie_domain')$secure
  425.         );
  426.  
  427.         $query $this->db->getQuery(true);
  428.  
  429.         if (empty($user->cookieLogin|| $options['response'!= 'Coookie')
  430.         {
  431.             // For users doing login from Joomla or other systems
  432.             $query->insert($this->db->quoteName('#__user_keys'));
  433.         }
  434.         else
  435.         {
  436.             $query
  437.                 ->update($this->db->quoteName('#__user_keys'))
  438.                 ->where($this->db->quoteName('user_id'' = ' $this->db->quote($options['user']->username))
  439.                 ->where($this->db->quoteName('series'' = ' $this->db->quote(base64_encode($rememberArray[1])))
  440.                 ->where($this->db->quoteName('uastring'' = ' $this->db->quote($cookieName));
  441.         }
  442.  
  443.         $query
  444.             ->set($this->db->quoteName('user_id'' = ' $this->db->quote($options['user']->username))
  445.             ->set($this->db->quoteName('time'' = ' $cookieLifetime)
  446.             ->set($this->db->quoteName('token'' = ' $this->db->quote($cryptedKey))
  447.             ->set($this->db->quoteName('series'' = ' $this->db->quote(base64_encode($series)))
  448.             ->set($this->db->quoteName('invalid'' = 0')
  449.             ->set($this->db->quoteName('uastring'' = ' $this->db->quote($cookieName));
  450.  
  451.         $this->db->setQuery($query)->execute();
  452.  
  453.         return true;
  454.     }
  455.  
  456.     /**
  457.      * This is where we delete any authentication cookie when a user logs out
  458.      *
  459.      * @param   array  $options  Array holding options (length, timeToExpiration)
  460.      *
  461.      * @return  boolean  True on success
  462.      *
  463.      * @since   3.2
  464.      */
  465.     public function onUserAfterLogout($options)
  466.     {
  467.         $rememberArray JUserHelper::getRememberCookieData();
  468.  
  469.         // There are no cookies to delete.
  470.         if ($rememberArray === false)
  471.         {
  472.             return true;
  473.         }
  474.  
  475.         list($privateKey$series$cookieName$rememberArray;
  476.  
  477.         // Remove the record from the database
  478.         $query $this->db->getQuery(true);
  479.  
  480.         $query
  481.             ->delete('#__user_keys')
  482.             ->where($this->db->quoteName('uastring'' = ' $this->db->quote($cookieName))
  483.             ->where($this->db->quoteName('series'' = ' $this->db->quote(base64_encode($series)))
  484.             ->where($this->db->quoteName('user_id'' = ' $this->db->quote($options['username']));
  485.  
  486.         $this->db->setQuery($query)->execute();
  487.  
  488.         // Destroy the cookie
  489.         $this->app->input->cookie->set($cookieNamefalsetime(42000$this->cookie_path$this->cookie_domain);
  490.  
  491.         return true;
  492.     }
  493.  
  494.     /**
  495.      * Method to set the default encryption for passwords
  496.      *
  497.      * @param   JRegistry  $userPluginParams  User plugin params
  498.      *
  499.      * @return  string  The default encryption method based on plugin parameters
  500.      *
  501.      * @since   3.2
  502.      */
  503.     public static function setDefaultEncryption($userPluginParams)
  504.     {
  505.         if ($userPluginParams->get('strong_passwords'== 1)
  506.         {
  507.             return 'bcrypt';
  508.         }
  509.         else
  510.         {
  511.             return 'md5-hex';
  512.         }
  513.     }
  514. }

Documentation generated on Tue, 19 Nov 2013 15:06:13 +0100 by phpDocumentor 1.4.3