Source for file user.php

Documentation is available at user.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Administrator
  4.  * @subpackage  com_users
  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.  * User model.
  14.  *
  15.  * @package     Joomla.Administrator
  16.  * @subpackage  com_users
  17.  * @since       1.6
  18.  */
  19. class UsersModelUser extends JModelAdmin
  20. {
  21.     /**
  22.      * Constructor.
  23.      *
  24.      * @param   array  $config  An optional associative array of configuration settings.
  25.      *
  26.      * @since   3.2
  27.      */
  28.     public function __construct($config array())
  29.     {
  30.         parent::__construct($config);
  31.  
  32.         // Load the Joomla! RAD layer
  33.         if (!defined('FOF_INCLUDED'))
  34.         {
  35.             include_once JPATH_LIBRARIES '/fof/include.php';
  36.         }
  37.     }
  38.  
  39.     /**
  40.      * Returns a reference to the a Table object, always creating it.
  41.      *
  42.      * @param   string  $type    The table type to instantiate
  43.      * @param   string  $prefix  A prefix for the table class name. Optional.
  44.      * @param   array   $config  Configuration array for model. Optional.
  45.      *
  46.      * @return  JTable  A database object
  47.      *
  48.      * @since   1.6
  49.     */
  50.     public function getTable($type 'User'$prefix 'JTable'$config array())
  51.     {
  52.         $table JTable::getInstance($type$prefix$config);
  53.  
  54.         return $table;
  55.     }
  56.  
  57.     /**
  58.      * Method to get a single record.
  59.      *
  60.      * @param   integer  $pk  The id of the primary key.
  61.      *
  62.      * @return  mixed  Object on success, false on failure.
  63.      *
  64.      * @since   1.6
  65.      */
  66.     public function getItem($pk null)
  67.     {
  68.         $result parent::getItem($pk);
  69.  
  70.         $result->tags new JHelperTags;
  71.         $result->tags->getTagIds($result->id'com_users.user');
  72.  
  73.         // Get the dispatcher and load the users plugins.
  74.         $dispatcher    JEventDispatcher::getInstance();
  75.         JPluginHelper::importPlugin('user');
  76.  
  77.         // Trigger the data preparation event.
  78.         $dispatcher->trigger('onContentPrepareData'array('com_users.user'$result));
  79.  
  80.         return $result;
  81.     }
  82.  
  83.     /**
  84.      * Method to get the record form.
  85.      *
  86.      * @param   array    $data      An optional array of data for the form to interogate.
  87.      * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not.
  88.      *
  89.      * @return  mixed  A JForm object on success, false on failure
  90.      *
  91.      * @since   1.6
  92.      */
  93.     public function getForm($data array()$loadData true)
  94.     {
  95.         $plugin JPluginHelper::getPlugin('user''joomla');
  96.         $pluginParams new JRegistry($plugin->params);
  97.  
  98.         // Get the form.
  99.         $form $this->loadForm('com_users.user''user'array('control' => 'jform''load_data' => $loadData));
  100.  
  101.         if (empty($form))
  102.         {
  103.             return false;
  104.         }
  105.  
  106.         // Passwords fields are required when mail to user is set to No in joomla user plugin
  107.         $userId $form->getValue('id');
  108.  
  109.         if ($userId === && $pluginParams->get('mail_to_user'=== "0")
  110.         {
  111.             $form->setFieldAttribute('password''required''true');
  112.             $form->setFieldAttribute('password2''required''true');
  113.         }
  114.  
  115.         return $form;
  116.     }
  117.  
  118.     /**
  119.      * Method to get the data that should be injected in the form.
  120.      *
  121.      * @return  mixed  The data for the form.
  122.      *
  123.      * @since   1.6
  124.      */
  125.     protected function loadFormData()
  126.     {
  127.         // Check the session for previously entered form data.
  128.         $data JFactory::getApplication()->getUserState('com_users.edit.user.data'array());
  129.  
  130.         if (empty($data))
  131.         {
  132.             $data $this->getItem();
  133.         }
  134.  
  135.         JPluginHelper::importPlugin('user');
  136.  
  137.         $this->preprocessData('com_users.profile'$data);
  138.  
  139.         return $data;
  140.     }
  141.  
  142.     /**
  143.      * Override JModelAdmin::preprocessForm to ensure the correct plugin group is loaded.
  144.      *
  145.      * @param   JForm   $form   A JForm object.
  146.      * @param   mixed   $data   The data expected for the form.
  147.      * @param   string  $group  The name of the plugin group to import (defaults to "content").
  148.      *
  149.      * @return  void 
  150.      *
  151.      * @since   1.6
  152.      * @throws  Exception if there is an error in the form event.
  153.      */
  154.     protected function preprocessForm(JForm $form$data$group 'user')
  155.     {
  156.         parent::preprocessForm($form$data$group);
  157.     }
  158.  
  159.     /**
  160.      * Method to save the form data.
  161.      *
  162.      * @param   array  $data  The form data.
  163.      *
  164.      * @return  boolean  True on success.
  165.      *
  166.      * @since   1.6
  167.      */
  168.     public function save($data)
  169.     {
  170.         $pk   (!empty($data['id'])) $data['id': (int) $this->getState('user.id');
  171.         $user JUser::getInstance($pk);
  172.  
  173.         $my JFactory::getUser();
  174.  
  175.         if ($data['block'&& $pk == $my->id && !$my->block)
  176.         {
  177.             $this->setError(JText::_('COM_USERS_USERS_ERROR_CANNOT_BLOCK_SELF'));
  178.  
  179.             return false;
  180.         }
  181.  
  182.         // Make sure that we are not removing ourself from Super Admin group
  183.         $iAmSuperAdmin $my->authorise('core.admin');
  184.  
  185.         if ($iAmSuperAdmin && $my->get('id'== $pk)
  186.         {
  187.             // Check that at least one of our new groups is Super Admin
  188.             $stillSuperAdmin false;
  189.             $myNewGroups $data['groups'];
  190.  
  191.             foreach ($myNewGroups as $group)
  192.             {
  193.                 $stillSuperAdmin ($stillSuperAdmin($stillSuperAdminJAccess::checkGroup($group'core.admin');
  194.             }
  195.  
  196.             if (!$stillSuperAdmin)
  197.             {
  198.                 $this->setError(JText::_('COM_USERS_USERS_ERROR_CANNOT_DEMOTE_SELF'));
  199.  
  200.                 return false;
  201.             }
  202.         }
  203.  
  204.         // Handle the two factor authentication setup
  205.         if (array_key_exists('twofactor'$data))
  206.         {
  207.             $twoFactorMethod $data['twofactor']['method'];
  208.  
  209.             // Get the current One Time Password (two factor auth) configuration
  210.             $otpConfig $this->getOtpConfig($pk);
  211.  
  212.             if ($twoFactorMethod != 'none')
  213.             {
  214.                 // Run the plugins
  215.                 FOFPlatform::getInstance()->importPlugin('twofactorauth');
  216.                 $otpConfigReplies FOFPlatform::getInstance()->runPlugins('onUserTwofactorApplyConfiguration'array($twoFactorMethod));
  217.  
  218.                 // Look for a valid reply
  219.                 foreach ($otpConfigReplies as $reply)
  220.                 {
  221.                     if (!is_object($reply|| empty($reply->method|| ($reply->method != $twoFactorMethod))
  222.                     {
  223.                         continue;
  224.                     }
  225.  
  226.                     $otpConfig->method $reply->method;
  227.                     $otpConfig->config $reply->config;
  228.  
  229.                     break;
  230.                 }
  231.  
  232.                 // Save OTP configuration.
  233.                 $this->setOtpConfig($pk$otpConfig);
  234.  
  235.                 // Generate one time emergency passwords if required (depleted or not set)
  236.                 if (empty($otpConfig->otep))
  237.                 {
  238.                     $oteps $this->generateOteps($pk);
  239.                 }
  240.             }
  241.             else
  242.             {
  243.                 $otpConfig->method 'none';
  244.                 $otpConfig->config array();
  245.                 $this->setOtpConfig($pk$otpConfig);
  246.             }
  247.  
  248.             // Unset the raw data
  249.             unset($data['twofactor']);
  250.  
  251.             // Reload the user record with the updated OTP configuration
  252.             $user->load($pk);
  253.         }
  254.  
  255.         // Bind the data.
  256.         if (!$user->bind($data))
  257.         {
  258.             $this->setError($user->getError());
  259.  
  260.             return false;
  261.         }
  262.  
  263.         // Store the data.
  264.         if (!$user->save())
  265.         {
  266.             $this->setError($user->getError());
  267.  
  268.             return false;
  269.         }
  270.  
  271.         $this->setState('user.id'$user->id);
  272.  
  273.         return true;
  274.     }
  275.  
  276.     /**
  277.      * Method to delete rows.
  278.      *
  279.      * @param   array  &$pks  An array of item ids.
  280.      *
  281.      * @return  boolean  Returns true on success, false on failure.
  282.      *
  283.      * @since   1.6
  284.      */
  285.     public function delete(&$pks)
  286.     {
  287.         $user  JFactory::getUser();
  288.         $table $this->getTable();
  289.         $pks   = (array) $pks;
  290.  
  291.         // Check if I am a Super Admin
  292.         $iAmSuperAdmin $user->authorise('core.admin');
  293.  
  294.         // Trigger the onUserBeforeSave event.
  295.         JPluginHelper::importPlugin('user');
  296.         $dispatcher JEventDispatcher::getInstance();
  297.  
  298.         if (in_array($user->id$pks))
  299.         {
  300.             $this->setError(JText::_('COM_USERS_USERS_ERROR_CANNOT_DELETE_SELF'));
  301.  
  302.             return false;
  303.         }
  304.  
  305.         // Iterate the items to delete each one.
  306.         foreach ($pks as $i => $pk)
  307.         {
  308.             if ($table->load($pk))
  309.             {
  310.                 // Access checks.
  311.                 $allow $user->authorise('core.delete''com_users');
  312.  
  313.                 // Don't allow non-super-admin to delete a super admin
  314.                 $allow (!$iAmSuperAdmin && JAccess::check($pk'core.admin')) false $allow;
  315.  
  316.                 if ($allow)
  317.                 {
  318.                     // Get users data for the users to delete.
  319.                     $user_to_delete JFactory::getUser($pk);
  320.  
  321.                     // Fire the onUserBeforeDelete event.
  322.                     $dispatcher->trigger('onUserBeforeDelete'array($table->getProperties()));
  323.  
  324.                     if (!$table->delete($pk))
  325.                     {
  326.                         $this->setError($table->getError());
  327.  
  328.                         return false;
  329.                     }
  330.                     else
  331.                     {
  332.                         // Trigger the onUserAfterDelete event.
  333.                         $dispatcher->trigger('onUserAfterDelete'array($user_to_delete->getProperties()true$this->getError()));
  334.                     }
  335.                 }
  336.                 else
  337.                 {
  338.                     // Prune items that you can't change.
  339.                     unset($pks[$i]);
  340.                     JError::raiseWarning(403JText::_('JERROR_CORE_DELETE_NOT_PERMITTED'));
  341.                 }
  342.             }
  343.             else
  344.             {
  345.                 $this->setError($table->getError());
  346.  
  347.                 return false;
  348.             }
  349.         }
  350.  
  351.         return true;
  352.     }
  353.  
  354.     /**
  355.      * Method to block user records.
  356.      *
  357.      * @param   array    &$pks   The ids of the items to publish.
  358.      * @param   integer  $value  The value of the published state
  359.      *
  360.      * @return  boolean  True on success.
  361.      *
  362.      * @since   1.6
  363.      */
  364.     public function block(&$pks$value 1)
  365.     {
  366.         $app        JFactory::getApplication();
  367.         $dispatcher JEventDispatcher::getInstance();
  368.         $user       JFactory::getUser();
  369.  
  370.         // Check if I am a Super Admin
  371.         $iAmSuperAdmin $user->authorise('core.admin');
  372.         $table         $this->getTable();
  373.         $pks           = (array) $pks;
  374.  
  375.         JPluginHelper::importPlugin('user');
  376.  
  377.         // Access checks.
  378.         foreach ($pks as $i => $pk)
  379.         {
  380.             if ($value == && $pk == $user->get('id'))
  381.             {
  382.                 // Cannot block yourself.
  383.                 unset($pks[$i]);
  384.                 JError::raiseWarning(403JText::_('COM_USERS_USERS_ERROR_CANNOT_BLOCK_SELF'));
  385.             }
  386.             elseif ($table->load($pk))
  387.             {
  388.                 $old   $table->getProperties();
  389.                 $allow $user->authorise('core.edit.state''com_users');
  390.  
  391.                 // Don't allow non-super-admin to delete a super admin
  392.                 $allow (!$iAmSuperAdmin && JAccess::check($pk'core.admin')) false $allow;
  393.  
  394.                 // Prepare the logout options.
  395.                 $options array(
  396.                     'clientid' => 0
  397.                 );
  398.  
  399.                 if ($allow)
  400.                 {
  401.                     // Skip changing of same state
  402.                     if ($table->block == $value)
  403.                     {
  404.                         unset($pks[$i]);
  405.                         continue;
  406.                     }
  407.  
  408.                     $table->block = (int) $value;
  409.  
  410.                     // If unblocking, also change password reset count to zero to unblock reset
  411.                     if ($table->block === 0)
  412.                     {
  413.                         $table->resetCount 0;
  414.                     }
  415.  
  416.                     // Allow an exception to be thrown.
  417.                     try
  418.                     {
  419.                         if (!$table->check())
  420.                         {
  421.                             $this->setError($table->getError());
  422.  
  423.                             return false;
  424.                         }
  425.  
  426.                         // Trigger the onUserBeforeSave event.
  427.                         $result $dispatcher->trigger('onUserBeforeSave'array($oldfalse$table->getProperties()));
  428.  
  429.                         if (in_array(false$resulttrue))
  430.                         {
  431.                             // Plugin will have to raise its own error or throw an exception.
  432.                             return false;
  433.                         }
  434.  
  435.                         // Store the table.
  436.                         if (!$table->store())
  437.                         {
  438.                             $this->setError($table->getError());
  439.  
  440.                             return false;
  441.                         }
  442.  
  443.                         // Trigger the onAftereStoreUser event
  444.                         $dispatcher->trigger('onUserAfterSave'array($table->getProperties()falsetruenull));
  445.                     }
  446.                     catch (Exception $e)
  447.                     {
  448.                         $this->setError($e->getMessage());
  449.  
  450.                         return false;
  451.                     }
  452.  
  453.                     // Log the user out.
  454.                     if ($value)
  455.                     {
  456.                         $app->logout($table->id$options);
  457.                     }
  458.                 }
  459.                 else
  460.                 {
  461.                     // Prune items that you can't change.
  462.                     unset($pks[$i]);
  463.                     JError::raiseWarning(403JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'));
  464.                 }
  465.             }
  466.         }
  467.  
  468.         return true;
  469.     }
  470.  
  471.     /**
  472.      * Method to activate user records.
  473.      *
  474.      * @param   array  &$pks  The ids of the items to activate.
  475.      *
  476.      * @return  boolean  True on success.
  477.      *
  478.      * @since   1.6
  479.      */
  480.     public function activate(&$pks)
  481.     {
  482.         $dispatcher    JEventDispatcher::getInstance();
  483.         $user        JFactory::getUser();
  484.  
  485.         // Check if I am a Super Admin
  486.         $iAmSuperAdmin $user->authorise('core.admin');
  487.         $table         $this->getTable();
  488.         $pks           = (array) $pks;
  489.  
  490.         JPluginHelper::importPlugin('user');
  491.  
  492.         // Access checks.
  493.         foreach ($pks as $i => $pk)
  494.         {
  495.             if ($table->load($pk))
  496.             {
  497.                 $old    $table->getProperties();
  498.                 $allow    $user->authorise('core.edit.state''com_users');
  499.  
  500.                 // Don't allow non-super-admin to delete a super admin
  501.                 $allow (!$iAmSuperAdmin && JAccess::check($pk'core.admin')) false $allow;
  502.  
  503.                 if (empty($table->activation))
  504.                 {
  505.                     // Ignore activated accounts.
  506.                     unset($pks[$i]);
  507.                 }
  508.                 elseif ($allow)
  509.                 {
  510.                     $table->block        0;
  511.                     $table->activation    '';
  512.  
  513.                     // Allow an exception to be thrown.
  514.                     try
  515.                     {
  516.                         if (!$table->check())
  517.                         {
  518.                             $this->setError($table->getError());
  519.  
  520.                             return false;
  521.                         }
  522.  
  523.                         // Trigger the onUserBeforeSave event.
  524.                         $result $dispatcher->trigger('onUserBeforeSave'array($oldfalse$table->getProperties()));
  525.  
  526.                         if (in_array(false$resulttrue))
  527.                         {
  528.                             // Plugin will have to raise it's own error or throw an exception.
  529.                             return false;
  530.                         }
  531.  
  532.                         // Store the table.
  533.                         if (!$table->store())
  534.                         {
  535.                             $this->setError($table->getError());
  536.  
  537.                             return false;
  538.                         }
  539.  
  540.                         // Fire the onAftereStoreUser event
  541.                         $dispatcher->trigger('onUserAfterSave'array($table->getProperties()falsetruenull));
  542.                     }
  543.                     catch (Exception $e)
  544.                     {
  545.                         $this->setError($e->getMessage());
  546.  
  547.                         return false;
  548.                     }
  549.                 }
  550.                 else
  551.                 {
  552.                     // Prune items that you can't change.
  553.                     unset($pks[$i]);
  554.                     JError::raiseWarning(403JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'));
  555.                 }
  556.             }
  557.         }
  558.  
  559.         return true;
  560.     }
  561.  
  562.     /**
  563.      * Method to perform batch operations on an item or a set of items.
  564.      *
  565.      * @param   array  $commands  An array of commands to perform.
  566.      * @param   array  $pks       An array of item ids.
  567.      * @param   array  $contexts  An array of item contexts.
  568.      *
  569.      * @return  boolean  Returns true on success, false on failure.
  570.      *
  571.      * @since   2.5
  572.      */
  573.     public function batch($commands$pks$contexts)
  574.     {
  575.         // Sanitize user ids.
  576.         $pks array_unique($pks);
  577.         JArrayHelper::toInteger($pks);
  578.  
  579.         // Remove any values of zero.
  580.         if (array_search(0$pkstrue))
  581.         {
  582.             unset($pks[array_search(0$pkstrue)]);
  583.         }
  584.  
  585.         if (empty($pks))
  586.         {
  587.             $this->setError(JText::_('COM_USERS_USERS_NO_ITEM_SELECTED'));
  588.  
  589.             return false;
  590.         }
  591.  
  592.         $done false;
  593.  
  594.         if (!empty($commands['group_id']))
  595.         {
  596.             $cmd JArrayHelper::getValue($commands'group_action''add');
  597.  
  598.             if (!$this->batchUser((int) $commands['group_id']$pks$cmd))
  599.             {
  600.                 return false;
  601.             }
  602.  
  603.             $done true;
  604.         }
  605.  
  606.         if (!$done)
  607.         {
  608.             $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION'));
  609.  
  610.             return false;
  611.         }
  612.  
  613.         // Clear the cache
  614.         $this->cleanCache();
  615.  
  616.         return true;
  617.     }
  618.  
  619.     /**
  620.      * Perform batch operations
  621.      *
  622.      * @param   integer  $group_id  The group ID which assignments are being edited
  623.      * @param   array    $user_ids  An array of user IDs on which to operate
  624.      * @param   string   $action    The action to perform
  625.      *
  626.      * @return  boolean  True on success, false on failure
  627.      *
  628.      * @since   1.6
  629.      */
  630.     public function batchUser($group_id$user_ids$action)
  631.     {
  632.         // Get the DB object
  633.         $db $this->getDbo();
  634.  
  635.         JArrayHelper::toInteger($user_ids);
  636.  
  637.         // Non-super admin cannot work with super-admin group
  638.         if ((!JFactory::getUser()->get('isRoot'&& JAccess::checkGroup($group_id'core.admin')) || $group_id 1)
  639.         {
  640.             $this->setError(JText::_('COM_USERS_ERROR_INVALID_GROUP'));
  641.  
  642.             return false;
  643.         }
  644.  
  645.         switch ($action)
  646.         {
  647.             // Sets users to a selected group
  648.             case 'set':
  649.                 $doDelete 'all';
  650.                 $doAssign true;
  651.                 break;
  652.  
  653.             // Remove users from a selected group
  654.             case 'del':
  655.                 $doDelete 'group';
  656.                 break;
  657.  
  658.             // Add users to a selected group
  659.             case 'add':
  660.             default:
  661.                 $doAssign true;
  662.                 break;
  663.         }
  664.  
  665.         // Remove the users from the group if requested.
  666.         if (isset($doDelete))
  667.         {
  668.             $query $db->getQuery(true);
  669.  
  670.             // Remove users from the group
  671.             $query->delete($db->quoteName('#__user_usergroup_map'))
  672.                 ->where($db->quoteName('user_id'' IN (' implode(','$user_ids')');
  673.  
  674.             // Only remove users from selected group
  675.             if ($doDelete == 'group')
  676.             {
  677.                 $query->where($db->quoteName('group_id'' = ' . (int) $group_id);
  678.             }
  679.  
  680.             $db->setQuery($query);
  681.  
  682.             try
  683.             {
  684.                 $db->execute();
  685.             }
  686.             catch (RuntimeException $e)
  687.             {
  688.                 $this->setError($e->getMessage());
  689.  
  690.                 return false;
  691.             }
  692.         }
  693.  
  694.         // Assign the users to the group if requested.
  695.         if (isset($doAssign))
  696.         {
  697.             $query $db->getQuery(true);
  698.  
  699.             // First, we need to check if the user is already assigned to a group
  700.             $query->select($db->quoteName('user_id'))
  701.                 ->from($db->quoteName('#__user_usergroup_map'))
  702.                 ->where($db->quoteName('group_id'' = ' . (int) $group_id);
  703.             $db->setQuery($query);
  704.             $users $db->loadColumn();
  705.  
  706.             // Build the values clause for the assignment query.
  707.             $query->clear();
  708.             $groups false;
  709.  
  710.             foreach ($user_ids as $id)
  711.             {
  712.                 if (!in_array($id$users))
  713.                 {
  714.                     $query->values($id ',' $group_id);
  715.                     $groups true;
  716.                 }
  717.             }
  718.  
  719.             // If we have no users to process, throw an error to notify the user
  720.             if (!$groups)
  721.             {
  722.                 $this->setError(JText::_('COM_USERS_ERROR_NO_ADDITIONS'));
  723.  
  724.                 return false;
  725.             }
  726.  
  727.             $query->insert($db->quoteName('#__user_usergroup_map'))
  728.                 ->columns(array($db->quoteName('user_id')$db->quoteName('group_id')));
  729.             $db->setQuery($query);
  730.  
  731.             try
  732.             {
  733.                 $db->execute();
  734.             }
  735.             catch (RuntimeException $e)
  736.             {
  737.                 $this->setError($e->getMessage());
  738.  
  739.                 return false;
  740.             }
  741.         }
  742.  
  743.         return true;
  744.     }
  745.  
  746.     /**
  747.      * Gets the available groups.
  748.      *
  749.      * @return  array  An array of groups
  750.      *
  751.      * @since   1.6
  752.      */
  753.     public function getGroups()
  754.     {
  755.         $user JFactory::getUser();
  756.  
  757.         if ($user->authorise('core.edit''com_users'&& $user->authorise('core.manage''com_users'))
  758.         {
  759.             $model JModelLegacy::getInstance('Groups''UsersModel'array('ignore_request' => true));
  760.  
  761.             return $model->getItems();
  762.         }
  763.         else
  764.         {
  765.             return null;
  766.         }
  767.     }
  768.  
  769.     /**
  770.      * Gets the groups this object is assigned to
  771.      *
  772.      * @param   integer  $userId  The user ID to retrieve the groups for
  773.      *
  774.      * @return  array  An array of assigned groups
  775.      *
  776.      * @since   1.6
  777.      */
  778.     public function getAssignedGroups($userId null)
  779.     {
  780.         $userId (!empty($userId)) $userId : (int) $this->getState('user.id');
  781.  
  782.         if (empty($userId))
  783.         {
  784.             $result array();
  785.  
  786.             $groupsIDs $this->getForm()->getValue('groups');
  787.  
  788.             if (!empty($groupsIDs))
  789.             {
  790.                 $result $groupsIDs;
  791.             }
  792.             else
  793.             {
  794.                 $config JComponentHelper::getParams('com_users');
  795.  
  796.                 if ($groupId $config->get('new_usertype'))
  797.                 {
  798.                     $result[$groupId;
  799.                 }
  800.             }
  801.         }
  802.         else
  803.         {
  804.             $result JUserHelper::getUserGroups($userId);
  805.         }
  806.  
  807.         return $result;
  808.     }
  809.  
  810.     /**
  811.      * Returns the one time password (OTP) â€“ a.k.a. two factor authentication â€“
  812.      * configuration for a particular user.
  813.      *
  814.      * @param   integer  $user_id  The numeric ID of the user
  815.      *
  816.      * @return  stdClass  An object holding the OTP configuration for this user
  817.      *
  818.      * @since   3.2
  819.      */
  820.     public function getOtpConfig($user_id null)
  821.     {
  822.         $user_id (!empty($user_id)) $user_id : (int) $this->getState('user.id');
  823.  
  824.         // Initialise
  825.         $otpConfig = (object) array(
  826.             'method' => 'none',
  827.             'config' => array(),
  828.             'otep'   => array()
  829.         );
  830.  
  831.         /**
  832.          * Get the raw data, without going through JUser (required in order to
  833.          * be able to modify the user record before logging in the user).
  834.          */
  835.         $db $this->getDbo();
  836.         $query $db->getQuery(true)
  837.             ->select('*')
  838.             ->from($db->qn('#__users'))
  839.             ->where($db->qn('id'' = ' $db->q($user_id));
  840.         $db->setQuery($query);
  841.         $item $db->loadObject();
  842.  
  843.         // Make sure this user does have OTP enabled
  844.         if (empty($item->otpKey))
  845.         {
  846.             return $otpConfig;
  847.         }
  848.  
  849.         // Get the encrypted data
  850.         list($method$encryptedConfigexplode(':'$item->otpKey2);
  851.         $encryptedOtep $item->otep;
  852.  
  853.         // Create an encryptor class
  854.         $key $this->getOtpConfigEncryptionKey();
  855.         $aes new FOFEncryptAes($key256);
  856.  
  857.         // Decrypt the data
  858.         $decryptedConfig $aes->decryptString($encryptedConfig);
  859.         $decryptedOtep $aes->decryptString($encryptedOtep);
  860.  
  861.         // Remove the null padding added during encryption
  862.         $decryptedConfig rtrim($decryptedConfig"\0");
  863.         $decryptedOtep rtrim($decryptedOtep"\0");
  864.  
  865.         // Update the configuration object
  866.         $otpConfig->method $method;
  867.         $otpConfig->config @json_decode($decryptedConfig);
  868.         $otpConfig->otep @json_decode($decryptedOtep);
  869.  
  870.         /*
  871.          * If the decryption failed for any reason we essentially disable the
  872.          * two-factor authentication. This prevents impossible to log in sites
  873.          * if the site admin changes the site secret for any reason.
  874.          */
  875.         if (is_null($otpConfig->config))
  876.         {
  877.             $otpConfig->config array();
  878.         }
  879.  
  880.         if (is_object($otpConfig->config))
  881.         {
  882.             $otpConfig->config = (array) $otpConfig->config;
  883.         }
  884.  
  885.         if (is_null($otpConfig->otep))
  886.         {
  887.             $otpConfig->otep array();
  888.         }
  889.  
  890.         if (is_object($otpConfig->otep))
  891.         {
  892.             $otpConfig->otep = (array) $otpConfig->otep;
  893.         }
  894.  
  895.         // Return the configuration object
  896.         return $otpConfig;
  897.     }
  898.  
  899.     /**
  900.      * Sets the one time password (OTP) â€“ a.k.a. two factor authentication â€“
  901.      * configuration for a particular user. The $otpConfig object is the same as
  902.      * the one returned by the getOtpConfig method.
  903.      *
  904.      * @param   integer   $user_id    The numeric ID of the user
  905.      * @param   stdClass  $otpConfig  The OTP configuration object
  906.      *
  907.      * @return  boolean  True on success
  908.      *
  909.      * @since   3.2
  910.      */
  911.     public function setOtpConfig($user_id$otpConfig)
  912.     {
  913.         $user_id (!empty($user_id)) $user_id : (int) $this->getState('user.id');
  914.  
  915.         $updates = (object) array(
  916.             'id'     => $user_id,
  917.             'otpKey' => '',
  918.             'otep'   => ''
  919.         );
  920.  
  921.         // Create an encryptor class
  922.         $key $this->getOtpConfigEncryptionKey();
  923.         $aes new FOFEncryptAes($key256);
  924.  
  925.         // Create the encrypted option strings
  926.         if (!empty($otpConfig->method&& ($otpConfig->method != 'none'))
  927.         {
  928.             $decryptedConfig json_encode($otpConfig->config);
  929.             $decryptedOtep json_encode($otpConfig->otep);
  930.             $updates->otpKey $otpConfig->method ':' $aes->encryptString($decryptedConfig);
  931.             $updates->otep $aes->encryptString($decryptedOtep);
  932.         }
  933.  
  934.         $db $this->getDbo();
  935.         $result $db->updateObject('#__users'$updates'id');
  936.  
  937.         return $result;
  938.     }
  939.  
  940.     /**
  941.      * Gets the symmetric encryption key for the OTP configuration data. It
  942.      * currently returns the site's secret.
  943.      *
  944.      * @return  string  The encryption key
  945.      *
  946.      * @since   3.2
  947.      */
  948.     public function getOtpConfigEncryptionKey()
  949.     {
  950.         return JFactory::getConfig()->get('secret');
  951.     }
  952.  
  953.     /**
  954.      * Gets the configuration forms for all two-factor authentication methods
  955.      * in an array.
  956.      *
  957.      * @param   integer  $user_id  The user ID to load the forms for (optional)
  958.      *
  959.      * @return  array 
  960.      *
  961.      * @since   3.2
  962.      */
  963.     public function getTwofactorform($user_id null)
  964.     {
  965.         $user_id (!empty($user_id)) $user_id : (int) $this->getState('user.id');
  966.  
  967.         $otpConfig $this->getOtpConfig($user_id);
  968.  
  969.         FOFPlatform::getInstance()->importPlugin('twofactorauth');
  970.  
  971.         return FOFPlatform::getInstance()->runPlugins('onUserTwofactorShowConfiguration'array($otpConfig$user_id));
  972.     }
  973.  
  974.     /**
  975.      * Generates a new set of One Time Emergency Passwords (OTEPs) for a given user.
  976.      *
  977.      * @param   integer  $user_id  The user ID
  978.      * @param   integer  $count    How many OTEPs to generate? Default: 10
  979.      *
  980.      * @return  array  The generated OTEPs
  981.      *
  982.      * @since   3.2
  983.      */
  984.     public function generateOteps($user_id$count 10)
  985.     {
  986.         $user_id (!empty($user_id)) $user_id : (int) $this->getState('user.id');
  987.  
  988.         // Initialise
  989.         $oteps array();
  990.  
  991.         // Get the OTP configuration for the user
  992.         $otpConfig $this->getOtpConfig($user_id);
  993.  
  994.         // If two factor authentication is not enabled, abort
  995.         if (empty($otpConfig->method|| ($otpConfig->method == 'none'))
  996.         {
  997.             return $oteps;
  998.         }
  999.  
  1000.         $salt "0123456789";
  1001.         $base strlen($salt);
  1002.         $length 16;
  1003.  
  1004.         for ($i 0$i $count$i++)
  1005.         {
  1006.             $makepass '';
  1007.             $random JCrypt::genRandomBytes($length 1);
  1008.             $shift ord($random[0]);
  1009.  
  1010.             for ($j 1$j <= $length++$j)
  1011.             {
  1012.                 $makepass .= $salt[($shift ord($random[$j])) $base];
  1013.                 $shift += ord($random[$j]);
  1014.             }
  1015.  
  1016.             $oteps[$makepass;
  1017.         }
  1018.  
  1019.         $otpConfig->otep $oteps;
  1020.  
  1021.         // Save the now modified OTP configuration
  1022.         $this->setOtpConfig($user_id$otpConfig);
  1023.  
  1024.         return $oteps;
  1025.     }
  1026.  
  1027.     /**
  1028.      * Checks if the provided secret key is a valid two factor authentication
  1029.      * secret key. If not, it will check it against the list of one time
  1030.      * emergency passwords (OTEPs). If it's a valid OTEP it will also remove it
  1031.      * from the user's list of OTEPs.
  1032.      *
  1033.      * This method will return true in the following conditions:
  1034.      * - The two factor authentication is not enabled
  1035.      * - You have provided a valid secret key for
  1036.      * - You have provided a valid OTEP
  1037.      *
  1038.      * You can define the following options in the $options array:
  1039.      * otp_config        The OTP (one time password, a.k.a. two factor auth)
  1040.      *                    configuration object. If not set we'll load it automatically.
  1041.      * warn_if_not_req    Issue a warning if you are checking a secret key against
  1042.      *                    a user account which doesn't have any two factor
  1043.      *                    authentication method enabled.
  1044.      * warn_irq_msg        The string to use for the warn_if_not_req warning
  1045.      *
  1046.      * @param   integer  $user_id    The user's numeric ID
  1047.      * @param   string   $secretkey  The secret key you want to check
  1048.      * @param   array    $options    Options; see above
  1049.      *
  1050.      * @return  boolean  True if it's a valid secret key for this user.
  1051.      *
  1052.      * @since   3.2
  1053.      */
  1054.     public function isValidSecretKey($user_id$secretkey$options array())
  1055.     {
  1056.         // Load the user's OTP (one time password, a.k.a. two factor auth) configuration
  1057.         if (!array_key_exists('otp_config'$options))
  1058.         {
  1059.             $otpConfig $this->getOtpConfig($user_id);
  1060.             $options['otp_config'$otpConfig;
  1061.         }
  1062.         else
  1063.         {
  1064.             $otpConfig $options['otp_config'];
  1065.         }
  1066.  
  1067.         // Check if the user has enabled two factor authentication
  1068.         if (empty($otpConfig->method|| ($otpConfig->method == 'none'))
  1069.         {
  1070.             // Load language
  1071.             $lang JFactory::getLanguage();
  1072.             $extension 'com_users';
  1073.             $source JPATH_ADMINISTRATOR '/components/' $extension;
  1074.  
  1075.             $lang->load($extensionJPATH_ADMINISTRATORnullfalsetrue)
  1076.                 || $lang->load($extension$sourcenullfalsetrue);
  1077.  
  1078.             $warn true;
  1079.             $warnMessage JText::_('COM_USERS_ERROR_SECRET_CODE_WITHOUT_TFA');
  1080.  
  1081.             if (array_key_exists('warn_if_not_req'$options))
  1082.             {
  1083.                 $warn $options['warn_if_not_req'];
  1084.             }
  1085.  
  1086.             if (array_key_exists('warn_irq_msg'$options))
  1087.             {
  1088.                 $warnMessage $options['warn_irq_msg'];
  1089.             }
  1090.  
  1091.             // Warn the user if he's using a secret code but he has not
  1092.             // enabled two factor auth in his account.
  1093.             if (!empty($secretkey&& $warn)
  1094.             {
  1095.                 try
  1096.                 {
  1097.                     $app JFactory::getApplication();
  1098.                     $app->enqueueMessage($warnMessage'warning');
  1099.                 }
  1100.                 catch (Exception $exc)
  1101.                 {
  1102.                     // This happens when we are in CLI mode. In this case
  1103.                     // no warning is issued
  1104.                     return true;
  1105.                 }
  1106.             }
  1107.  
  1108.             return true;
  1109.         }
  1110.  
  1111.         $credentials array(
  1112.             'secretkey' => $secretkey,
  1113.         );
  1114.  
  1115.         // Load the Joomla! RAD layer
  1116.         if (!defined('FOF_INCLUDED'))
  1117.         {
  1118.             include_once JPATH_LIBRARIES '/fof/include.php';
  1119.         }
  1120.  
  1121.         // Try to validate the OTP
  1122.         FOFPlatform::getInstance()->importPlugin('twofactorauth');
  1123.  
  1124.         $otpAuthReplies FOFPlatform::getInstance()->runPlugins('onUserTwofactorAuthenticate'array($credentials$options));
  1125.  
  1126.         $check false;
  1127.  
  1128.         /*
  1129.          * This looks like noob code but DO NOT TOUCH IT and do not convert
  1130.          * to in_array(). During testing in_array() inexplicably returned
  1131.          * null when the OTEP begins with a zero! o_O
  1132.          */
  1133.         if (!empty($otpAuthReplies))
  1134.         {
  1135.             foreach ($otpAuthReplies as $authReply)
  1136.             {
  1137.                 $check $check || $authReply;
  1138.             }
  1139.         }
  1140.  
  1141.         // Fall back to one time emergency passwords
  1142.         if (!$check)
  1143.         {
  1144.             $check $this->isValidOtep($user_id$secretkey$otpConfig);
  1145.         }
  1146.  
  1147.         return $check;
  1148.     }
  1149.  
  1150.     /**
  1151.      * Checks if the supplied string is a valid one time emergency password
  1152.      * (OTEP) for this user. If it is it will be automatically removed from the
  1153.      * user's list of OTEPs.
  1154.      *
  1155.      * @param   integer  $user_id    The user ID against which you are checking
  1156.      * @param   string   $otep       The string you want to test for validity
  1157.      * @param   object   $otpConfig  Optional; the two factor authentication configuration (automatically fetched if not set)
  1158.      *
  1159.      * @return  boolean  True if it's a valid OTEP or if two factor auth is not
  1160.      *                    enabled in this user's account.
  1161.      *
  1162.      * @since   3.2
  1163.      */
  1164.     public function isValidOtep($user_id$otep$otpConfig null)
  1165.     {
  1166.         if (is_null($otpConfig))
  1167.         {
  1168.             $otpConfig $this->getOtpConfig($user_id);
  1169.         }
  1170.  
  1171.         // Did the user use an OTEP instead?
  1172.         if (empty($otpConfig->otep))
  1173.         {
  1174.             if (empty($otpConfig->method|| ($otpConfig->method == 'none'))
  1175.             {
  1176.                 // Two factor authentication is not enabled on this account.
  1177.                 // Any string is assumed to be a valid OTEP.
  1178.                 return true;
  1179.             }
  1180.             else
  1181.             {
  1182.                 /**
  1183.                  * Two factor authentication enabled and no OTEPs defined. The
  1184.                  * user has used them all up. Therefore anything he enters is
  1185.                  * an invalid OTEP.
  1186.                  */
  1187.                 return false;
  1188.             }
  1189.         }
  1190.  
  1191.         // Clean up the OTEP (remove dashes, spaces and other funny stuff
  1192.         // our beloved users may have unwittingly stuffed in it)
  1193.         $otep filter_var($otepFILTER_SANITIZE_NUMBER_INT);
  1194.         $otep str_replace('-'''$otep);
  1195.  
  1196.         $check false;
  1197.  
  1198.         // Did we find a valid OTEP?
  1199.         if (in_array($otep$otpConfig->otep))
  1200.         {
  1201.             // Remove the OTEP from the array
  1202.             $otpConfig->otep array_diff($otpConfig->oteparray($otep));
  1203.  
  1204.             $this->setOtpConfig($user_id$otpConfig);
  1205.  
  1206.             // Return true; the OTEP was a valid one
  1207.             $check true;
  1208.         }
  1209.  
  1210.         return $check;
  1211.     }
  1212. }

Documentation generated on Tue, 19 Nov 2013 15:16:28 +0100 by phpDocumentor 1.4.3