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.53 2004/09/18 19:08:48 dufuz 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.  
  75.     /**
  76.      * Has the current user successfully logged in?
  77.      * Default: false
  78.      *
  79.      * @access protected
  80.      * @var    boolean 
  81.      * @see    LiveUser_Auth_Common::isActive
  82.      */
  83.     var $loggedIn = null;
  84.  
  85.     /**
  86.      * Timestamp of last login (previous to currentLogin)
  87.      *
  88.      * @access protected
  89.      * @var    integer 
  90.      */
  91.     var $lastLogin = 0;
  92.  
  93.     /**
  94.      * Timestamp of current login (last to be written)
  95.      *
  96.      * @access protected
  97.      * @var    integer 
  98.      */
  99.     var $currentLogin = 0;
  100.  
  101.     /**
  102.      * Number of hours that must pass between two logins
  103.      * to be counted as a new login. Comes in handy in
  104.      * some situations. Default: 12
  105.      *
  106.      * @access protected
  107.      * @var    integer 
  108.      */
  109.     var $loginTimeout = 12;
  110.  
  111.     /**
  112.      * Auth lifetime in seconds
  113.      *
  114.      * If this variable is set to 0, auth never expires
  115.      *
  116.      * @access protected
  117.      * @var    integer 
  118.      */
  119.     var $expireTime = 0;
  120.  
  121.     /**
  122.      * Maximum time of idleness in seconds
  123.      *
  124.      * Idletime gets refreshed each time, init() is called. If this
  125.      * variable is set to 0, idle time is never checked.
  126.      *
  127.      * @access protected
  128.      * @var    integer 
  129.      */
  130.     var $idleTime = 0;
  131.  
  132.     /**
  133.      * Allow multiple users in the database to have the same
  134.      * login handle. Default: false.
  135.      *
  136.      * @access protected
  137.      * @var    boolean 
  138.      */
  139.     var $allowDuplicateHandles = false;
  140.  
  141.     /**
  142.      * Set posible encryption modes.
  143.      *
  144.      * @access protected
  145.      * @var    array 
  146.      */
  147.     var $encryptionModes = array('MD5'   => 'MD5',
  148.                                  'PLAIN' => 'PLAIN',
  149.                                  'RC4'   => 'RC4',
  150.                                  'SHA1'  => 'SHA1');
  151.  
  152.  
  153.     /**
  154.      * Defines the algorithm used for encrypting/decrypting
  155.      * passwords. Default: "MD5".
  156.      *
  157.      * @access protected
  158.      * @var    string 
  159.      */
  160.     var $passwordEncryptionMode = 'MD5';
  161.  
  162.     /**
  163.      * Defines the array index number of the LoginManager?s "backends" property.
  164.      *
  165.      * @access protected
  166.      * @var    integer 
  167.      */
  168.     var $backendArrayIndex = 0;
  169.  
  170.     /**
  171.      * Indicates if backend module initialized correctly. If yes,
  172.      * true, if not false. Backend module won't initialize if the
  173.      * init value (usually an object or resource handle that
  174.      * identifies the backend to be used) is not of the required
  175.      * type.
  176.      *
  177.      * @access protected
  178.      * @var    boolean 
  179.      */
  180.     var $init_ok = false;
  181.  
  182.     /**
  183.      * Error stack
  184.      *
  185.      * @access protected
  186.      * @var    PEAR_ErrorStack 
  187.      */
  188.     var $_stack = null;
  189.  
  190.     /**
  191.      * Class constructor. Feel free to override in backend subclasses.
  192.      *
  193.      * @access protected
  194.      * @var    array     configuration options
  195.      * @return void 
  196.      */
  197.     function LiveUser_Auth_Common($connectOptions)
  198.     {
  199.         $this->_stack = &PEAR_ErrorStack::singleton('LiveUser');
  200.  
  201.         if (is_array($connectOptions)) {
  202.             foreach ($connectOptions as $key => $value{
  203.                 if (isset($this->$key)) {
  204.                     $this->$key $value;
  205.                 }
  206.             }
  207.         }
  208.     }
  209.  
  210.     /**
  211.      * store all properties in an array
  212.      *
  213.      * @access  public
  214.      * @return  array 
  215.      */
  216.     function freeze()
  217.     {
  218.         $propertyValues = array(
  219.             'handle'       => $this->handle,
  220.             'passwd'       => $this->passwd,
  221.             'authUserId'   => $this->authUserId,
  222.             'isActive'     => $this->isActive,
  223.             'loggedIn'     => $this->loggedIn,
  224.             'lastLogin'    => $this->lastLogin,
  225.             'currentLogin' => $this->currentLogin,
  226.         );
  227.         if (isset($this->authTableCols['optional'])) {
  228.             $propertyValues['authTableCols']['optional'$this->authTableCols['optional'];
  229.         }
  230.         if (isset($this->authTableCols['custom'])) {
  231.             $propertyValues['authTableCols']['custom'$this->authTableCols['custom'];
  232.         }
  233.         return $propertyValues;
  234.     }
  235.  
  236.     /**
  237.      * properly disconnect from resources
  238.      *
  239.      * @access  public
  240.      * @return  void 
  241.      */
  242.     function disconnect()
  243.     {
  244.     }
  245.  
  246.     /**
  247.      * Reinitializes properties
  248.      *
  249.      * @access  public
  250.      * @param   array  $propertyValues 
  251.      * @return  void 
  252.      */
  253.     function unfreeze($propertyValues)
  254.     {
  255.         foreach ($propertyValues as $key => $value{
  256.             $this->{$key$value;
  257.         }
  258.     // end func unfreeze
  259.  
  260.     /**
  261.      * Decrypts a password so that it can be compared with the user
  262.      * input. Uses the algorithm defined in the passwordEncryptionMode
  263.      * property.
  264.      *
  265.      * @param  string the encrypted password
  266.      * @return string The decrypted password
  267.      */
  268.     function decryptPW($encryptedPW)
  269.     {
  270.         $decryptedPW 'Encryption type not supported.';
  271.  
  272.         switch (strtoupper($this->passwordEncryptionMode)) {
  273.             case 'PLAIN':
  274.                 $decryptedPW $encryptedPW;
  275.                 break;
  276.             case 'MD5':
  277.                 // MD5 can't be decoded, so return the string unmodified
  278.                 $decryptedPW $encryptedPW;
  279.                 break;
  280.             case 'RC4':
  281.                 if (!is_object($this->rc4)) {
  282.                     $rc4 =LiveUser::CryptRC4Factory($this->_options['cookie']['secret']);
  283.                     if (!$rc4{
  284.                         return false;
  285.                     }
  286.                     $this->rc4 =$rc4;
  287.                 }
  288.                 $decryptedPW $encryptedPW;
  289.                 $this->rc4->decrypt($decryptedPW);
  290.                 break;
  291.             case 'SHA1':
  292.                 // SHA1 can't be decoded, so return the string unmodified
  293.                 $decryptedPW $encryptedPW;
  294.                 break;
  295.         }
  296.  
  297.         return $decryptedPW;
  298.     }
  299.  
  300.     /**
  301.      * Encrypts a password for storage in a backend container.
  302.      * Uses the algorithm defined in the passwordEncryptionMode
  303.      * property.
  304.      *
  305.      * @param string  encryption type
  306.      * @return string The encrypted password
  307.      */
  308.     function encryptPW($plainPW)
  309.     {
  310.         $encryptedPW 'Encryption type not supported.';
  311.  
  312.         switch (strtoupper($this->passwordEncryptionMode)) {
  313.             case 'PLAIN':
  314.                 $encryptedPW $plainPW;
  315.                 break;
  316.             case 'MD5':
  317.                 $encryptedPW md5($plainPW);
  318.                 break;
  319.             case 'RC4':
  320.                 if (!is_object($this->rc4)) {
  321.                     $rc4 =LiveUser::CryptRC4Factory($this->_options['cookie']['secret']);
  322.                     if (!$rc4{
  323.                         return false;
  324.                     }
  325.                     $this->rc4 =$rc4;
  326.                 }
  327.                 $encryptedPW $plainPW;
  328.                 $this->rc4->crypt($encryptedPW);
  329.                 break;
  330.             case 'SHA1':
  331.                 if (!function_exists('sha1')) {
  332.                         $this->_stack->push(LIVEUSER_ERROR_NOT_SUPPORTED,
  333.                             'exception'array()'SHA1 function doesn\'t exist. Upgrade your PHP version');
  334.                         return false;
  335.                 }
  336.                 $encryptedPW sha1($plainPW);
  337.                 break;
  338.         }
  339.  
  340.         return $encryptedPW;
  341.     }
  342.  
  343.     /**
  344.      * Checks if there's enough time between lastLogin
  345.      * and current login (now) to count as a new login.
  346.      *
  347.      * @access public
  348.      * @return boolean  true if it is a new login, false if not
  349.      */
  350.     function isNewLogin()
  351.     {
  352.         $meantime $this->loginTimeout * 3600;
  353.         if (time(>= $this->lastLogin + $meantime{
  354.             return true;
  355.         else {
  356.             return false;
  357.         }
  358.     }
  359.  
  360.     /**
  361.      * Tries to make a login with the given handle and password.
  362.      * If $checkpw is set to false, the password won't be
  363.      * validated and the user will be logged in anyway. Set this
  364.      * option if you want to allow your users to be
  365.      * authenticated by a simple cookie... however, this is
  366.      * NOT RECOMMENDED !!!
  367.      * In any case, a user can't login if he's not active.
  368.      *
  369.      * @param string   user handle
  370.      * @param string   user password
  371.      * @param boolean  check password ? useful for some backends like LDAP
  372.      * @param boolean  update the last login data ?
  373.      */
  374.     function login($handle$passwd$checkpw = true$updateLastLogin = true)
  375.     {
  376.         // Init value: Has user data successfully been read?
  377.         $success        = false;
  378.         // Init value: Is user logged in?
  379.         $this->loggedIn = false;
  380.         // Read user data from database
  381.         if ($this->allowDuplicateHandles == true || $checkpw == true{
  382.             // If duplicate handles are allowed or the password _has_
  383.             // to be checked, only read in data if a matching user is found
  384.             $success $this->_readUserData($handle$passwd);
  385.         else {
  386.             // If duplicate handles are not allowed or the password
  387.             // doesn't need to be checked, just read in the data based
  388.             // on the handle
  389.             $success $this->_readUserData($handle);
  390.         }
  391.  
  392.         // If login is successful (user data has been read)
  393.         if ($success == true{
  394.             $pwCheck = false; // Init value
  395.  
  396.             // Just in case: Some databases will return whitespace when using
  397.             // CHAR fields to store passwords, so we?ll remove it.
  398.             $this->passwd = trim($this->passwd);
  399.  
  400.             // ...check again if we have to check the password...
  401.             if ($checkpw == true{
  402.                 // If yes, does the password from the database match the given one?
  403.                 if (strtoupper($this->passwordEncryptionMode== 'MD5'
  404.                         && $this->passwd == $this->encryptPW($passwd)){
  405.                     // If yes, set pwCheck Flag
  406.                     $pwCheck = true;
  407.                 else if ($this->passwd == $passwd{
  408.                     // If yes, set pwCheck Flag
  409.                     $pwCheck = true;
  410.                 }
  411.             else {
  412.                 // We don't have to check for the password, so set the pwCheck Flag
  413.                 // regardless of the user's input
  414.                 $pwCheck = true;
  415.             }
  416.  
  417.             // ...we still need to check if this user is declared active and
  418.             // if the pwCheck Flag is set to true...
  419.             if ($this->isActive != false && $pwCheck == true{
  420.                 // ...and if so, we have a successful login (hooray)!
  421.                 $this->loggedIn = true;
  422.                 $this->currentLogin = time();
  423.             }
  424.         }
  425.  
  426.         // In case Login was successful, check if this can be counted
  427.         // as a _new_ login by definition...
  428.         if ($updateLastLogin == true && $this->isNewLogin(== true && $this->loggedIn == true{
  429.             $this->_updateUserData();
  430.         }
  431.     }
  432.  
  433.     /**
  434.      * Writes current values for user back to the database.
  435.      * This method does nothing in the base class and is supposed to
  436.      * be overridden in subclasses according to the supported backend.
  437.      *
  438.      * @access private
  439.      * @return void 
  440.      */
  441.     function _updateUserData()
  442.     {
  443.         $this->_stack->push(LIVEUSER_ERROR_NOT_SUPPORTED'exception');
  444.     }
  445.  
  446.     /**
  447.      * Reads auth_user_id, passwd, is_active flag
  448.      * lastlogin timestamp from the database
  449.      * If only $handle is given, it will read the data
  450.      * from the first user with that handle and return
  451.      * true on success.
  452.      * If $handle and $passwd are given, it will try to
  453.      * find the first user with both handle and password
  454.      * matching and return true on success (this allows
  455.      * multiple users having the same handle but different
  456.      * passwords - yep, some people want this).
  457.      * If no match is found, false is being returned.
  458.      *
  459.      * Again, this does nothing in the base class. The
  460.      * described functionality must be implemented in a
  461.      * subclass overriding this method.
  462.      *
  463.      * @access private
  464.      * @param  string  user handle
  465.      * @param  boolean user password
  466.      * @return void 
  467.      */
  468.     function _readUserData($handle$passwd = false)
  469.     {
  470.         $this->_stack->push(LIVEUSER_ERROR_NOT_SUPPORTED'exception',
  471.             array('feature' => '_readUserData'));
  472.         return false;
  473.     }
  474.  
  475.     /**
  476.      * Helper function that checks if there is a user in
  477.      * the database who's matching the given parameters.
  478.      * If $checkHandle is given and $checkPW is set to
  479.      * false, it only checks if a user with that handle
  480.      * exists. If only $checkPW is given and $checkHandle
  481.      * is set to false, it will check if there exists a
  482.      * user with that password. If both values are set to
  483.      * anything but false, it will find the first user in
  484.      * the database with both values matching.
  485.      * Please note:
  486.      * - If no match was found, the return value is false
  487.      * - If a match was found, the auth_user_id from the database
  488.      *   is being returned
  489.      * Whatever is returned, please keep in mind that this
  490.      * function only searches for the _first_ occurence
  491.      * of the search values in the database. So when you
  492.      * have multiple users with the same handle, only the
  493.      * ID of the first one is returned. Same goes for
  494.      * passwords. Searching for both password and handle
  495.      * should be pretty safe, though - having more than
  496.      * one user with the same handle/password combination
  497.      * in the database would be pretty stupid anyway.
  498.      *
  499.      * Again, this does nothing in the base class. The
  500.      * described functionality must be implemented in a
  501.      * subclass overriding this method.
  502.      *
  503.      * @param  boolean check handle ?
  504.      * @param  boolean check password ?
  505.      * @return mixed  user id when there is a match, false otherwise
  506.      */
  507.     function userExists($checkHandle = false$checkPW = false)
  508.     {
  509.         $this->_stack->push(LIVEUSER_ERROR_NOT_SUPPORTED'exception',
  510.             array('feature' => 'userExists'));
  511.             return false;
  512.     }
  513.  
  514.     /**
  515.      * Function returns the inquired value if it exists in the class.
  516.      *
  517.      * @param  string   Name of the property to be returned.
  518.      * @return mixed    null, a value or an array.
  519.      */
  520.     function getProperty($what)
  521.     {
  522.         $that = null;
  523.         if (isset($this->$what)) {
  524.             $that $this->$what;
  525.         elseif (!empty($this->authTableCols['optional']&& in_array($what$this->authTableCols['optional'])) {
  526.             $that $this->authTableCols['optional'][$what];
  527.         elseif (!empty($this->authTableCols['custom']&& in_array($what$this->authTableCols['custom'])) {
  528.             $that $this->authTableCols['custom'][$what];
  529.         }
  530.         return $that;
  531.     }
  532. }
  533. ?>

Documentation generated on Mon, 11 Mar 2019 13:56:15 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.