LiveUser
[ class tree: LiveUser ] [ index: LiveUser ] [ all elements ]

Source for file Common.php

Documentation is available at Common.php

  1. <?php
  2. // LiveUser: A framework for authentication and authorization in PHP applications
  3. // Copyright (C) 2002-2003 Markus Wolff
  4. //
  5. // This library is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU Lesser General Public
  7. // License as published by the Free Software Foundation; either
  8. // version 2.1 of the License, or (at your option) any later version.
  9. //
  10. // This library is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. // Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public
  16. // License along with this library; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19. /**
  20.  * This class provides a set of functions for implementing a user
  21.  * authorisation system on live websites. All authorisation
  22.  * backends/containers must be extensions of this base class.
  23.  *
  24.  * Requirements:
  25.  * - When using "DB" backend:
  26.  *   PEAR::DB database abstraction layer
  27.  * - LiveUser admin GUI for easy user administration and setup of
  28.  *   authorisation areas and rights
  29.  *
  30.  * @author   Markus Wolff <wolff@21st.de>
  31.  * @version  $Id: Common.php,v 1.7 2004/12/18 21:54:05 lsmith Exp $
  32.  * @package  LiveUser
  33.  * @category authentication
  34.  */
  35. {
  36.     /**
  37.      * The handle (username) of the current user
  38.      *
  39.      * @access protected
  40.      * @var    string 
  41.      */
  42.     var $handle = '';
  43.  
  44.     /**
  45.      * The password of the current user as given to the
  46.      * login() method.
  47.      *
  48.      * @access protected
  49.      * @var    string 
  50.      */
  51.     var $passwd = '';
  52.  
  53.     /**
  54.      * Current user's database record id
  55.      *
  56.      * @access protected
  57.      * @var    integer 
  58.      */
  59.     var $authUserId = 0;
  60.  
  61.     /**
  62.      * Is the current user allowed to login at all? If false,
  63.      * a call to login() will not set $logged_in to true, even
  64.      * if handle and password were submitted correctly. This is
  65.      * useful when you want your users to be activated by an
  66.      * administrator before they can actually use your application.
  67.      * Default: false
  68.      *
  69.      * @access protected
  70.      * @var    boolean 
  71.      * @see    LiveUser_Auth_Common::loggedIn
  72.      */
  73.     var $isActive = null;
  74.     var $ownerUserId = null;
  75.     var $ownerGroupId = null;
  76.  
  77.     /**
  78.      * Has the current user successfully logged in?
  79.      * Default: false
  80.      *
  81.      * @access protected
  82.      * @var    boolean 
  83.      * @see    LiveUser_Auth_Common::isActive
  84.      */
  85.     var $loggedIn = null;
  86.  
  87.     /**
  88.      * Timestamp of last login (previous to currentLogin)
  89.      *
  90.      * @access protected
  91.      * @var    integer 
  92.      */
  93.     var $lastLogin = 0;
  94.  
  95.     /**
  96.      * Timestamp of current login (last to be written)
  97.      *
  98.      * @access protected
  99.      * @var    integer 
  100.      */
  101.     var $currentLogin = 0;
  102.  
  103.     /**
  104.      * Number of hours that must pass between two logins
  105.      * to be counted as a new login. Comes in handy in
  106.      * some situations. Default: 12
  107.      *
  108.      * @access protected
  109.      * @var    integer 
  110.      */
  111.     var $loginTimeout = 12;
  112.  
  113.     /**
  114.      * Auth lifetime in seconds
  115.      *
  116.      * If this variable is set to 0, auth never expires
  117.      *
  118.      * @access protected
  119.      * @var    integer 
  120.      */
  121.     var $expireTime = 0;
  122.  
  123.     /**
  124.      * Maximum time of idleness in seconds
  125.      *
  126.      * Idletime gets refreshed each time, init() is called. If this
  127.      * variable is set to 0, idle time is never checked.
  128.      *
  129.      * @access protected
  130.      * @var    integer 
  131.      */
  132.     var $idleTime = 0;
  133.  
  134.     /**
  135.      * Allow multiple users in the database to have the same
  136.      * login handle. Default: false.
  137.      *
  138.      * @access protected
  139.      * @var    boolean 
  140.      */
  141.     var $allowDuplicateHandles = false;
  142.  
  143.     /**
  144.      * Set posible encryption modes.
  145.      *
  146.      * @access protected
  147.      * @var    array 
  148.      */
  149.     var $encryptionModes = array('MD5'   => 'MD5',
  150.                                  'PLAIN' => 'PLAIN',
  151.                                  'RC4'   => 'RC4',
  152.                                  'SHA1'  => 'SHA1');
  153.  
  154.  
  155.     /**
  156.      * Defines the algorithm used for encrypting/decrypting
  157.      * passwords. Default: "MD5".
  158.      *
  159.      * @access protected
  160.      * @var    string 
  161.      */
  162.     var $passwordEncryptionMode = 'MD5';
  163.  
  164.     /**
  165.      * Defines the array index number of the LoginManager?s "backends" property.
  166.      *
  167.      * @access protected
  168.      * @var    integer 
  169.      */
  170.     var $backendArrayIndex = 0;
  171.  
  172.     /**
  173.      * Error stack
  174.      *
  175.      * @access protected
  176.      * @var    PEAR_ErrorStack 
  177.      */
  178.     var $_stack = null;
  179.  
  180.     /**
  181.     * Property values
  182.     *
  183.     * @access public
  184.     * @var array 
  185.     */
  186.     var $propertyValues = array();
  187.  
  188.     /**
  189.      * The name associated with this auth container. The name is used
  190.      * when adding users from this container to the reference table
  191.      * in the permission container. This way it is possible to see
  192.      * from which auth container the user data is coming from.
  193.      *
  194.      * @var    string 
  195.      * @access public
  196.      */
  197.     var $containerName = null;
  198.  
  199.     /**
  200.      * External values to check (config settings)
  201.      *
  202.      * @var    array 
  203.      * @access public
  204.      */
  205.     var $externalValues = array();
  206.  
  207.     /**
  208.      * Class constructor. Feel free to override in backend subclasses.
  209.      *
  210.      * @access protected
  211.      * @var    array     configuration options
  212.      * @return void 
  213.      */
  214.     function LiveUser_Auth_Common($connectOptions$containerName)
  215.     {
  216.         $this->_stack = &PEAR_ErrorStack::singleton('LiveUser');
  217.  
  218.         $this->containerName = $containerName;
  219.         if (is_array($connectOptions)) {
  220.             foreach ($connectOptions as $key => $value{
  221.                 if (isset($this->$key)) {
  222.                     $this->$key $value;
  223.                 }
  224.             }
  225.         }
  226.     }
  227.  
  228.     /**
  229.      * store all properties in an array
  230.      *
  231.      * @access  public
  232.      * @return  array 
  233.      */
  234.     function freeze()
  235.     {
  236.         // get values from $this->externalValues['values'] and
  237.         // store them into $this->propertyValues['storedExternalValues']
  238.         $this->setExternalValues();
  239.  
  240.         $propertyValues = array(
  241.             'handle'       => $this->handle,
  242.             'authUserId'   => $this->authUserId,
  243.             'isActive'     => $this->isActive,
  244.             'loggedIn'     => $this->loggedIn,
  245.             'lastLogin'    => $this->lastLogin,
  246.             'currentLogin' => $this->currentLogin,
  247.             'ownerGroupId' => $this->ownerGroupId,
  248.             'ownerUserId'  => $this->ownerUserId
  249.         );
  250.  
  251.         $propertyValues['storedExternalValues'= null;
  252.         if (isset($this->propertyValues['storedExternalValues']&&
  253.             !empty($this->propertyValues['storedExternalValues'])
  254.         {
  255.             $propertyValues['storedExternalValues'$this->propertyValues['storedExternalValues'];
  256.         }
  257.  
  258.         $propertyValues['custom'= isset($this->propertyValues['custom'])
  259.             ? $this->propertyValues['custom': null;
  260.  
  261.         return $propertyValues;
  262.     }
  263.  
  264.     /**
  265.      * properly disconnect from resources
  266.      *
  267.      * @access  public
  268.      * @return  void 
  269.      */
  270.     function disconnect()
  271.     {
  272.     }
  273.  
  274.     /**
  275.      * Reinitializes properties
  276.      *
  277.      * @access  public
  278.      * @param   array  $propertyValues 
  279.      * @return  boolean 
  280.      */
  281.     function unfreeze($propertyValues)
  282.     {
  283.         foreach ($propertyValues as $key => $value{
  284.             if (is_array($value)) {
  285.                 $this->propertyValues[$key$value;
  286.             else {
  287.                 $this->{$key$value;
  288.             }
  289.         }
  290.  
  291.         return $this->externalValuesMatch();
  292.     // end func unfreeze
  293.  
  294.     /**
  295.      * Decrypts a password so that it can be compared with the user
  296.      * input. Uses the algorithm defined in the passwordEncryptionMode
  297.      * property.
  298.      *
  299.      * @param  string the encrypted password
  300.      * @return string The decrypted password
  301.      */
  302.     function decryptPW($encryptedPW)
  303.     {
  304.         $decryptedPW 'Encryption type not supported.';
  305.  
  306.         switch (strtoupper($this->passwordEncryptionMode)) {
  307.             case 'PLAIN':
  308.                 $decryptedPW $encryptedPW;
  309.                 break;
  310.             case 'MD5':
  311.                 // MD5 can't be decoded, so return the string unmodified
  312.                 $decryptedPW $encryptedPW;
  313.                 break;
  314.             case 'RC4':
  315.                 if (!is_object($this->rc4)) {
  316.                     $rc4 =LiveUser::CryptRC4Factory($this->_options['cookie']['secret']);
  317.                     if (!$rc4{
  318.                         return false;
  319.                     }
  320.                     $this->rc4 =$rc4;
  321.                 }
  322.                 $decryptedPW $encryptedPW;
  323.                 $this->rc4->decrypt($decryptedPW);
  324.                 break;
  325.             case 'SHA1':
  326.                 // SHA1 can't be decoded, so return the string unmodified
  327.                 $decryptedPW $encryptedPW;
  328.                 break;
  329.         }
  330.  
  331.         return $decryptedPW;
  332.     }
  333.  
  334.     /**
  335.      * Encrypts a password for storage in a backend container.
  336.      * Uses the algorithm defined in the passwordEncryptionMode
  337.      * property.
  338.      *
  339.      * @param string  encryption type
  340.      * @return string The encrypted password
  341.      */
  342.     function encryptPW($plainPW)
  343.     {
  344.         $encryptedPW 'Encryption type not supported.';
  345.  
  346.         switch (strtoupper($this->passwordEncryptionMode)) {
  347.             case 'PLAIN':
  348.                 $encryptedPW $plainPW;
  349.                 break;
  350.             case 'MD5':
  351.                 $encryptedPW md5($plainPW);
  352.                 break;
  353.             case 'RC4':
  354.                 if (!is_object($this->rc4)) {
  355.                     $rc4 =LiveUser::CryptRC4Factory($this->_options['cookie']['secret']);
  356.                     if (!$rc4{
  357.                         return false;
  358.                     }
  359.                     $this->rc4 =$rc4;
  360.                 }
  361.                 $encryptedPW $plainPW;
  362.                 $this->rc4->crypt($encryptedPW);
  363.                 break;
  364.             case 'SHA1':
  365.                 if (!function_exists('sha1')) {
  366.                         $this->_stack->push(LIVEUSER_ERROR_NOT_SUPPORTED,
  367.                             'exception'array()'SHA1 function doesn\'t exist. Upgrade your PHP version');
  368.                         return false;
  369.                 }
  370.                 $encryptedPW sha1($plainPW);
  371.                 break;
  372.         }
  373.  
  374.         return $encryptedPW;
  375.     }
  376.  
  377.     /**
  378.      * Checks if there's enough time between lastLogin
  379.      * and current login (now) to count as a new login.
  380.      *
  381.      * @access public
  382.      * @return boolean  true if it is a new login, false if not
  383.      */
  384.     function isNewLogin()
  385.     {
  386.         $meantime $this->loginTimeout * 3600;
  387.         if (time(>= $this->lastLogin + $meantime{
  388.             return true;
  389.         else {
  390.             return false;
  391.         }
  392.     }
  393.  
  394.     /**
  395.      * Tries to make a login with the given handle and password.
  396.      * If $checkpw is set to false, the password won't be
  397.      * validated and the user will be logged in anyway. Set this
  398.      * option if you want to allow your users to be
  399.      * authenticated by a simple cookie... however, this is
  400.      * NOT RECOMMENDED !!!
  401.      * In any case, a user can't login if he's not active.
  402.      *
  403.      * @param string   user handle
  404.      * @param string   user password
  405.      * @param boolean  check password ? useful for some backends like LDAP
  406.      * @param boolean  update the last login data ?
  407.      */
  408.     function login($handle$passwd$checkpw = true$updateLastLogin = true)
  409.     {
  410.         // Init value: Has user data successfully been read?
  411.         $success        = false;
  412.         // Init value: Is user logged in?
  413.         $this->loggedIn = false;
  414.         // Read user data from database
  415.         if ($this->allowDuplicateHandles == true || $checkpw == true{
  416.             // If duplicate handles are allowed or the password _has_
  417.             // to be checked, only read in data if a matching user is found
  418.             $success $this->_readUserData($handle$passwd);
  419.         else {
  420.             // If duplicate handles are not allowed or the password
  421.             // doesn't need to be checked, just read in the data based
  422.             // on the handle
  423.             $success $this->_readUserData($handle);
  424.         }
  425.  
  426.         // If login is successful (user data has been read)
  427.         if ($success == true{
  428.             $pwCheck = false; // Init value
  429.  
  430.             // Just in case: Some databases will return whitespace when using
  431.             // CHAR fields to store passwords, so we?ll remove it.
  432.             $this->passwd = trim($this->passwd);
  433.  
  434.             // ...check again if we have to check the password...
  435.             if ($checkpw == true{
  436.                 // If yes, does the password from the database match the given one?
  437.                 if (strtoupper($this->passwordEncryptionMode== 'MD5'
  438.                         && $this->passwd == $this->encryptPW($passwd)){
  439.                     // If yes, set pwCheck Flag
  440.                     $pwCheck = true;
  441.                 else if ($this->passwd == $passwd{
  442.                     // If yes, set pwCheck Flag
  443.                     $pwCheck = true;
  444.                 }
  445.             else {
  446.                 // We don't have to check for the password, so set the pwCheck Flag
  447.                 // regardless of the user's input
  448.                 $pwCheck = true;
  449.             }
  450.  
  451.             // ...we still need to check if this user is declared active and
  452.             // if the pwCheck Flag is set to true...
  453.             if ($this->isActive != false && $pwCheck == true{
  454.                 // ...and if so, we have a successful login (hooray)!
  455.                 $this->loggedIn = true;
  456.                 $this->currentLogin = time();
  457.             }
  458.         }
  459.  
  460.         // In case Login was successful, check if this can be counted
  461.         // as a _new_ login by definition...
  462.         if ($updateLastLogin == true && $this->isNewLogin(== true && $this->loggedIn == true{
  463.             $this->_updateUserData();
  464.         }
  465.     }
  466.  
  467.     /**
  468.      * Writes current values for user back to the database.
  469.      * This method does nothing in the base class and is supposed to
  470.      * be overridden in subclasses according to the supported backend.
  471.      *
  472.      * @access private
  473.      * @return void 
  474.      */
  475.     function _updateUserData()
  476.     {
  477.         $this->_stack->push(LIVEUSER_ERROR_NOT_SUPPORTED'exception');
  478.     }
  479.  
  480.     /**
  481.      * Reads auth_user_id, passwd, is_active flag
  482.      * lastlogin timestamp from the database
  483.      * If only $handle is given, it will read the data
  484.      * from the first user with that handle and return
  485.      * true on success.
  486.      * If $handle and $passwd are given, it will try to
  487.      * find the first user with both handle and password
  488.      * matching and return true on success (this allows
  489.      * multiple users having the same handle but different
  490.      * passwords - yep, some people want this).
  491.      * If no match is found, false is being returned.
  492.      *
  493.      * Again, this does nothing in the base class. The
  494.      * described functionality must be implemented in a
  495.      * subclass overriding this method.
  496.      *
  497.      * @access private
  498.      * @param  string  user handle
  499.      * @param  boolean user password
  500.      * @return void 
  501.      */
  502.     function _readUserData($handle$passwd = false)
  503.     {
  504.         $this->_stack->push(LIVEUSER_ERROR_NOT_SUPPORTED'exception',
  505.             array('feature' => '_readUserData'));
  506.         return false;
  507.     }
  508.  
  509.     /**
  510.      * Helper function that checks if there is a user in
  511.      * the database who's matching the given parameters.
  512.      * If $checkHandle is given and $checkPW is set to
  513.      * false, it only checks if a user with that handle
  514.      * exists. If only $checkPW is given and $checkHandle
  515.      * is set to false, it will check if there exists a
  516.      * user with that password. If both values are set to
  517.      * anything but false, it will find the first user in
  518.      * the database with both values matching.
  519.      * Please note:
  520.      * - If no match was found, the return value is false
  521.      * - If a match was found, the auth_user_id from the database
  522.      *   is being returned
  523.      * Whatever is returned, please keep in mind that this
  524.      * function only searches for the _first_ occurence
  525.      * of the search values in the database. So when you
  526.      * have multiple users with the same handle, only the
  527.      * ID of the first one is returned. Same goes for
  528.      * passwords. Searching for both password and handle
  529.      * should be pretty safe, though - having more than
  530.      * one user with the same handle/password combination
  531.      * in the database would be pretty stupid anyway.
  532.      *
  533.      * Again, this does nothing in the base class. The
  534.      * described functionality must be implemented in a
  535.      * subclass overriding this method.
  536.      *
  537.      * @param  boolean check handle ?
  538.      * @param  boolean check password ?
  539.      * @return mixed  user id when there is a match, false otherwise
  540.      */
  541.     function userExists($checkHandle = false$checkPW = false)
  542.     {
  543.         $this->_stack->push(LIVEUSER_ERROR_NOT_SUPPORTED'exception',
  544.             array('feature' => 'userExists'));
  545.         return false;
  546.     }
  547.  
  548.     /**
  549.      * Function returns the inquired value if it exists in the class.
  550.      *
  551.      * @param  string   Name of the property to be returned.
  552.      * @return mixed    null, a value or an array.
  553.      */
  554.     function getProperty($what)
  555.     {
  556.         $that = null;
  557.         $lwhat strtolower($what);
  558.         if (isset($this->$what)) {
  559.             $that $this->$what;
  560.         elseif (isset($this->propertyValues['custom'][$lwhat])) {
  561.             $that $this->propertyValues['custom'][$lwhat];
  562.         }
  563.         return $that;
  564.     }
  565.  
  566.     /**
  567.      * Creates associative array of values from $externalValues['values'] with $keysToCheck
  568.      *
  569.      * @access public
  570.      */
  571.     function setExternalValues()
  572.     {
  573.         if (isset($this->externalValues['keysToCheck']&&
  574.             is_array($this->externalValues['keysToCheck'])
  575.         {
  576.             foreach ($this->externalValues['keysToCheck'as $keyToCheck{
  577.                 if (isset($this->externalValues['values'][$keyToCheck])) {
  578.                     $this->propertyValues['storedExternalValues'][$keyToCheck=
  579.                         md5($this->externalValues['values'][$keyToCheck]);
  580.                 }
  581.             }
  582.         }
  583.     }
  584.  
  585.     /**
  586.      * Check if the stored external values match the current external values
  587.      *
  588.      * @access  public
  589.      * @param   array   $values 
  590.      */
  591.     function externalValuesMatch()
  592.     {
  593.         if (isset($this->propertyValues['storedExternalValues']&&
  594.             is_array($this->propertyValues['storedExternalValues'])
  595.         {
  596.             foreach ($this->propertyValues['storedExternalValues'as $keyToCheck => $storedValue{
  597.                 // return false if any one of the stored values does not match the current value
  598.                 if (!isset($this->externalValues['values'][$keyToCheck]||
  599.                     md5($this->externalValues['values'][$keyToCheck]!= $storedValue
  600.                 {
  601.                     return false;
  602.                 }
  603.             }
  604.         }
  605.         return true;
  606.     }
  607. }
  608. ?>

Documentation generated on Mon, 11 Mar 2019 14:00:07 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.