OSDN Git Service

CHANGE:: ログイン処理の見直し
authorsakamocchi <o-takashi@sakamocchi.jp>
Mon, 27 Feb 2012 18:27:35 +0000 (03:27 +0900)
committersakamocchi <o-takashi@sakamocchi.jp>
Mon, 27 Feb 2012 18:27:35 +0000 (03:27 +0900)
globalfunctions.phpのログイン処理のほとんどをMEMBERクラスに移動。
将来の拡張に備え、MEMBER::$algorismとMEMBER::hash()を新設。

nucleus/libs/MEMBER.php
nucleus/libs/globalfunctions.php

index 877cff3..73689fc 100644 (file)
@@ -22,6 +22,7 @@ class MEMBER {
        // 1 when authenticated, 0 when not
        public $loggedin = 0;
        public $password;               // not the actual password, but rather a MD5 hash
+       private $algorism = 'md5';
        
        public $cookiekey;              // value that should also be in the client cookie to allow authentication
        
@@ -35,27 +36,57 @@ class MEMBER {
        public $canlogin = 0;           // (either 0 or 1)
        public $notes;
        public $autosave = 1;           // if the member use the autosave draft function
+       private $locale = '';
        
-       /*
-        * NOTE: $locale value obsoleted $language value since version 4.0
-        */
+       /* NOTE: $locale value obsoleted $language value since version 4.0 */
        public $language = '';
-       public $locale = '';
        
        /**
+        * MEMBER::__construct()
         * Constructor for a member object
-        */             
-       public function MEMBER()
+        * 
+        * @param       Void
+        * @return      Void
+        * 
+        */
+       public function __construct()
        {
-               // do nothing
+               /* secure cookie key settings (either 'none', 0, 8, 16, 24, or 32) */
+               if ( !array_key_exists('secureCookieKey', $CONF) )
+               {
+                       $CONF['secureCookieKey'] = 24;
+               }
+               
+               switch( $CONF['secureCookieKey'] )
+               {
+                       case 8:
+                               $CONF['secureCookieKeyIP'] = preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
+                               break;
+                       case 16:
+                               $CONF['secureCookieKeyIP'] = preg_replace('/\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
+                               break;
+                       case 24:
+                               $CONF['secureCookieKeyIP'] = preg_replace('/\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
+                               break;
+                       case 32:
+                               $CONF['secureCookieKeyIP'] = serverVar('REMOTE_ADDR');
+                               break;
+                       default:
+                               $CONF['secureCookieKeyIP'] = '';
+               }
+               
                return;
        }
-
+       
        /**
+        * MEMBER::createFromName()
         * Create a member object for a given displayname
         *
-        * @static               
-        */             
+        * @static      
+        * @param       String  $displayname    login name
+        * @return      Object  member object
+        * 
+        */
        public static function &createFromName($displayname)
        {
                $mem = new MEMBER();
@@ -64,9 +95,11 @@ class MEMBER {
        }
 
        /**
+        * MEMBER::createFromID()
         * Create a member object for a given ID
         *
         * @static      
+        * @param       Integer $id     id for member
         */
        public static function &createFromID($id)
        {
@@ -75,29 +108,73 @@ class MEMBER {
                return $mem;
        }
        
+       /**
+        * MEMBER::readFromName()
+        * Read member table in database
+        * 
+        * @param       String  $displayname    login name
+        * @return      Object  SQL resource
+        * 
+        */
        public function readFromName($displayname)
        {
                return $this->read("mname='".sql_real_escape_string($displayname)."'");
        }
        
+       /**
+        * MEMBER::readFromID()
+        * Read member table in database
+        * 
+        * @param       Integer $id     id for member
+        * @return      Object  SQL resource
+        * 
+        */
        public function readFromID($id)
        {
                return $this->read("mnumber=" . intval($id));
        }
        
-       /*
+       /**
+        * MEMBER::hash()
+        * hash the target string
+        * 
+        * @param       String  $string target string
+        * @return      Void    hashed string
+        */
+       public function hash($string)
+       {
+               switch ( $this->algorism )
+               {
+                       case 'md5':
+                       default:
+                               $string = md5($string);
+               }
+               
+               return $string;
+       }
+       
+       /**
+        * MEMBER::login()
         * Tries to login as a given user.
         * Returns true when succeeded, returns false when failed
         * 3.40 adds CustomLogin event
+        * 
+        * @param       String  $login  login name for member
+        * @param       String  $password       password for member
+        * @param       Integer $shared whether the user agent is shared or not
+        * 
         */
-       public function login($login, $password)
+       public function login($login, $password, $shared=1)
        {
-               global $manager;
+               global $CONF, $errormessage, $manager;
                
+               /* TODO: validation for $login, $password, $shared */
                if ( $login == '' || $password == '' )
                {
                        return 0;
                }
+               /* limiting the length of password to avoid hash collision */
+               $password=i18n::substr($password, 0, 40);
                
                $success = 0;
                $allowlocal = 1;
@@ -112,33 +189,126 @@ class MEMBER {
                {
                        $this->loggedin = ( $this->readFromName($login) && $this->checkPassword($password) );
                }
+               
+               /* login failed */
+               if ( !$this->loggedin )
+               {
+                       $trimlogin = trim($login);
+                       if ( empty($trimlogin) )
+                       {
+                               $errormessage = "Please enter a username.";
+                       }
+                       else 
+                       {
+                               $errormessage = 'Login failed for ' . $login;
+                       }
+                       $manager->notify('LoginFailed', array('username' => $login) );
+                       ACTIONLOG::add(INFO, $errormessage);
+               }
+               /* login success */
+               else
+               {
+                       $this->newCookieKey();
+                       $this->setCookies($shared);
+                       
+                       if ( $CONF['secureCookieKey'] !== 'none' )
+                       {
+                               /* secure cookie key */
+                               $this->setCookieKey($this->hash($this->getCookieKey().$CONF['secureCookieKeyIP']));
+                               $this->write();
+                       }
+                       
+                       $errormessage = '';
+                       $manager->notify('LoginSuccess', array('member' => &$member, 'username' => $login) );
+                       ACTIONLOG::add(INFO, "Login successful for $login (sharedpc=$shared)");
+               }
+               
                return $this->loggedin;
        }
        
-       /*
+       /**
+        * MEMBER::cookielogin()
         * Login using cookie key
+        * 
+        * @param       String  $login  not used
+        * @param       String  $cookiekey      not used
+        * @return      Boolean login or not
         */
-       public function cookielogin($login, $cookiekey)
+       public function cookielogin($login='', $cookiekey='')
        {
-               $this->loggedin = ( $this->readFromName($login) && $this->checkCookieKey($cookiekey) );
+               global $CONF, $manager;
+               
+               if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") )
+               {
+                       /* Cookie Authentication */
+                       $ck = cookieVar("{$CONF['CookiePrefix']}loginkey");
+                       
+                       /* TODO: validation for each cookie values */
+                       
+                       /* limiting the length of password to avoid hash collision */
+                       $ck = i18n::substr($ck,0,32);
+                       if ( $CONF['secureCookieKey']!=='none' )
+                       {
+                               $ck = $this->hash("{$ck}{$CONF['secureCookieKeyIP']}");
+                       }
+                       $this->loggedin = ( $this->readFromName(cookieVar("{$CONF['CookiePrefix']}user")) && $this->checkCookieKey($ck) );
+                       unset($ck);
+                       
+                       /* renew cookies when not on a shared computer */
+                       if ( $res && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) )
+                       {
+                               $member->setCookieKey(cookieVar("{$CONF['CookiePrefix']}loginkey"));
+                               $member->setCookies();
+                       }
+               }
                return $this->loggedin;
        }
        
+       /**
+        * MEMBER::logout()
+        * logout and expire cookie
+        * 
+        * @param       Void
+        * @return      Void
+        */
        public function logout()
        {
+               global $CONF, $manager;
+               
+               if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") )
+               {
+                       /* remove cookies on logout */
+                       setcookie("{$CONF['CookiePrefix']}user", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
+                       setcookie("{$CONF['CookiePrefix']}loginkey", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
+                       $manager->notify('Logout', array('username' => cookieVar("{$CONF['CookiePrefix']}user") ) );
+               }
+               
                $this->loggedin = 0;
                return;
        }
        
+       /**
+        * MEMBER::isLoggedIn()
+        * return member is loggedin or not
+        * 
+        * @param       Void
+        * @return      Void
+        */
        public function isLoggedIn()
        {
                return $this->loggedin;
        }
        
-       /*
+       /**
+        * MEMBER:read()
         * Read member information from the database 
+        * 
+        * @param       String  $where  where statement
+        * @return      Resource        SQL resource
+        * 
         */
-       public function read($where) {
+       public function read($where)
+       {
                // read info
                $query =  'SELECT * FROM '.sql_table('member') . ' WHERE ' . $where;
                
@@ -161,9 +331,14 @@ class MEMBER {
                return sql_num_rows($res);
        }
        
-       /*
+       /**
+        * MEMBER::isBlogAdmin()
         * Returns true if member is an admin for the given blog
         * (returns false if not a team member)
+        * 
+        * @param       Integer $blogid weblog id
+        * @return      Integer weblog admin or not
+        * 
         */
        public function isBlogAdmin($blogid)
        {
@@ -561,7 +736,7 @@ class MEMBER {
        
        public function checkPassword($pw)
        {
-               return (md5($pw) == $this->getPassword());
+               return ($this->hash($pw) == $this->getPassword());
        }
        
        public function getRealName()
@@ -591,7 +766,7 @@ class MEMBER {
 
        public function setPassword($pwd)
        {
-               $this->password = md5($pwd);
+               $this->password = $this->hash($pwd);
        }
 
        public function getCookieKey()
@@ -605,7 +780,7 @@ class MEMBER {
        public function newCookieKey()
        {
                mt_srand( (double) microtime() * 1000000);
-               $this->cookiekey = md5(uniqid(mt_rand()));
+               $this->cookiekey = $this->hash(uniqid(mt_rand()));
                $this->write();
                return $this->cookiekey;
        }
@@ -801,7 +976,7 @@ class MEMBER {
                
                $name = sql_real_escape_string($name);
                $realname = sql_real_escape_string($realname);
-               $password = sql_real_escape_string(md5($password));
+               $password = sql_real_escape_string($this->hash($password));
                $email = sql_real_escape_string($email);
                $url = sql_real_escape_string($url);
                $admin = intval($admin);
@@ -877,7 +1052,7 @@ class MEMBER {
                {
                        // generate a random key
                        srand((double)microtime()*1000000);
-                       $key = md5(uniqid(rand(), true));
+                       $key = $this->hash(uniqid(rand(), true));
                        
                        // attempt to add entry in database
                        // add in database as non-active
index fb3156d..d156839 100644 (file)
@@ -97,14 +97,6 @@ $CONF['CategoryURL']         = $CONF['Self'];
 */
 
 /*
- * NOTE: this should be removed when releasing 4.0
- * switch URLMode back to normal when $CONF['Self'] ends in .php
- * this avoids urls like index.php/item/13/index.php/item/15
-if (!isset($CONF['URLMode']) || (($CONF['URLMode'] == 'pathinfo') && (substr($CONF['Self'], strlen($CONF['Self']) - 4) == '.php'))) {
-    $CONF['URLMode'] = 'normal';
-}*/
-
-/*
  * Set these to 1 to allow viewing of future items or draft items
  * Should really never do this, but can be useful for some plugins that might need to
  * Could cause some other issues if you use future posts otr drafts
@@ -272,8 +264,7 @@ $CONF['CategoryURL'] = $CONF['Self'];
  *switch URLMode back to normal when $CONF['Self'] ends in .php
  * this avoids urls like index.php/item/13/index.php/item/15
  */
-if ( !array_key_exists('URLMode', $CONF)
- || (($CONF['URLMode'] == 'pathinfo')
+if ( !array_key_exists('URLMode', $CONF) || (($CONF['URLMode'] == 'pathinfo')
   && (i18n::substr($CONF['Self'], i18n::strlen($CONF['Self']) - 4) == '.php')) )
 {
        $CONF['URLMode'] = 'normal';
@@ -287,175 +278,41 @@ if ( ($CONF['DisableJsTools'] == 0)
        $CONF['DisableJsTools'] = 2;
 }
 
-/* login if cookies set*/
 $member = new MEMBER();
 
-/* secure cookie key settings (either 'none', 0, 8, 16, 24, or 32) */
-if ( !array_key_exists('secureCookieKey', $CONF) )
-{
-       $CONF['secureCookieKey'] = 24;
-}
-switch( $CONF['secureCookieKey'] )
-{
-       case 8:
-               $CONF['secureCookieKeyIP'] = preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
-               break;
-       case 16:
-               $CONF['secureCookieKeyIP'] = preg_replace('/\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
-               break;
-       case 24:
-               $CONF['secureCookieKeyIP'] = preg_replace('/\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
-               break;
-       case 32:
-               $CONF['secureCookieKeyIP'] = serverVar('REMOTE_ADDR');
-               break;
-       default:
-               $CONF['secureCookieKeyIP'] = '';
-}
-
-/*
- * login/logout when required or renew cookies
- *  and decide locale on this session before plugin event generates
- */
 if ( $action == 'login' )
 {
-       /* Form Authentication */
        $login = postVar('login');
-       $pw = postVar('password');
-       /* shared computer or not */
+       $password = postVar('password');
        $shared = intPostVar('shared');
-       /* avoid md5 collision by using a long key */
-       $pw=i18n::substr($pw,0,40);
-       
-       if ( $member->login($login, $pw) )
-       {
-               $member->newCookieKey();
-               $member->setCookies($shared);
-               
-               if ( $CONF['secureCookieKey'] !== 'none' )
-               {
-                       /* secure cookie key */
-                       $member->setCookieKey(md5($member->getCookieKey().$CONF['secureCookieKeyIP']));
-                       $member->write();
-               }
-               
-               /* allows direct access to parts of the admin area after logging in */
-               if ( $nextaction )
-               {
-                       $action = $nextaction;
-               }
-               
-               /* NOTE: include translation file and set locale */
-               $locale = include_translation($locale, $member);
-               i18n::set_current_locale($locale);
-               
-               $manager->notify('LoginSuccess', array('member' => &$member, 'username' => $login) );
-               $errormessage = '';
-               ACTIONLOG::add(INFO, "Login successful for $login (sharedpc=$shared)");
-       }
-       else
-       {
-               /* errormessage for [%errordiv%] */
-               $trimlogin = trim($login);
-               if ( empty($trimlogin) )
-               {
-                       $errormessage = "Please enter a username.";
-               }
-               else 
-               {
-                       $errormessage = 'Login failed for ' . $login;
-               } 
-               
-               /* NOTE: include translation file and set locale */
-               $locale = include_translation($locale);
-               i18n::set_current_locale($locale);
-               
-               $manager->notify('LoginFailed', array('username' => $login) );
-               ACTIONLOG::add(INFO, $errormessage);
-       }
+       $member->login($login, $password, $shared);
 }
-
-/*
- * TODO: this should be removed when releasing 4.0
-Backed out for now: See http://forum.nucleuscms.org/viewtopic.php?t=3684 for details
-elseif ( serverVar('PHP_AUTH_USER') && serverVar('PHP_AUTH_PW') )
+elseif ( ($action == 'logout') )
 {
-       // HTTP Authentication
-       $login  = serverVar('PHP_AUTH_USER');
-       $pw     = serverVar('PHP_AUTH_PW');
-       
-       if ( $member->login($login, $pw) )
-       {
-               $manager->notify('LoginSuccess',array('member' => &$member));
-               ACTIONLOG::add(INFO, "HTTP authentication successful for $login");
-       }
-       else
-       {
-               $manager->notify('LoginFailed',array('username' => $login));
-               ACTIONLOG::add(INFO, 'HTTP authentication failed for ' . $login);
-               
-               //Since bad credentials, generate an apropriate error page
-               header("WWW-Authenticate: Basic realm=\"Nucleus CMS {$nucleus['version']}\"");
-               header('HTTP/1.0 401 Unauthorized');
-               echo 'Invalid username or password';
-               exit;
-       }
+       $member->logout();
 }
-*/
-
-elseif ( ($action == 'logout')
-      && (!headers_sent())
-      && cookieVar($CONF['CookiePrefix'] . 'user') )
-{
-       /* remove cookies on logout */
-       setcookie($CONF['CookiePrefix'] . 'user', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
-       setcookie($CONF['CookiePrefix'] . 'loginkey', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
-       
-       /* NOTE: include translation file and set locale */
-       $locale = include_translation($locale);
-       i18n::set_current_locale($locale);
-       
-       $manager->notify('Logout', array('username' => cookieVar($CONF['CookiePrefix'] . 'user') ) );
-}
-elseif ( cookieVar($CONF['CookiePrefix'] . 'user') )
+else
 {
-       /* Cookie Authentication */
-       $ck=cookieVar($CONF['CookiePrefix'] . 'loginkey');
-       /* 
-        * secure cookie key
-        * avoid md5 collision by using a long key
-        */
-       $ck = i18n::substr($ck,0,32);
-       if ( $CONF['secureCookieKey']!=='none' )
-       {
-               $ck = md5($ck.$CONF['secureCookieKeyIP']);
-       }
-       $res = $member->cookielogin(cookieVar($CONF['CookiePrefix'] . 'user'), $ck );
-       unset($ck);
-       
-       /* renew cookies when not on a shared computer */
-       if ( $res
-         && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1)
-         && (!headers_sent() ) )
-       {
-               $member->setCookieKey(cookieVar($CONF['CookiePrefix'] . 'loginkey'));
-               $member->setCookies();
-       }
-       
-       /* NOTE: include translation file and set locale */
-       $locale = include_translation($locale, $member);
-       i18n::set_current_locale($locale);
+       $member->cookielogin();
 }
-else
+
+/* NOTE: include translation file and set locale */
+if ( $member->isLoggedIn() && !$member->getLocale())
 {
-       /* NOTE: include translation file and set locale */
-       $locale = include_translation($locale);
-       i18n::set_current_locale($locale);
+       $locale = $member->getLocale();
 }
+include_translation($locale);
+i18n::set_current_locale($locale);
 
 /* login completed */
 $manager->notify('PostAuthentication', array('loggedIn' => $member->isLoggedIn() ) );
 
+/* next action */
+if ( $member->isLoggedIn() && $nextaction )
+{
+       $action = $nextaction;
+}
+
 /*
  * Release ticket for plugin
  */
@@ -497,21 +354,6 @@ if ( !headers_sent() )
        }
 }
 
-/*
-Backed out for now: See http://forum.nucleuscms.org/viewtopic.php?t=3684 for details
-
-// To remove after v2.5 is released and translation files have been updated.
-// Including this makes sure that translation files for v2.5beta can still be used for v2.5final
-// without having weird _SETTINGS_EXTAUTH string showing up in the admin area.
-if (!defined('_MEMBERS_BYPASS'))
-{
-    define('_SETTINGS_EXTAUTH',         'Enable External Authentication');
-    define('_WARNING_EXTAUTH',          'Warning: Enable only if needed.');
-    define('_MEMBERS_BYPASS',           'Use External Authentication');
-}
-*/
-
-/* make sure the archivetype skinvar keeps working when _ARCHIVETYPE_XXX not defined */
 if ( !defined('_ARCHIVETYPE_MONTH') )
 {
        define('_ARCHIVETYPE_DAY', 'day');
@@ -653,6 +495,7 @@ if ( $CONF['URLMode'] == 'pathinfo' )
                }
        }
 }
+
 /*
  * PostParseURL is a place to cleanup any of the path-related global variables before the selector function is run.
  * It has 2 values in the data in case the original virtualpath is needed, but most the use will be in tweaking
@@ -752,23 +595,12 @@ $manager->notify(
        /**
         * This function decide which locale is used and include translation
         * @param       string  $locale locale name referring to 'language tags' defined in RFC 5646
-        * @param mixed $member member object
+        * @return      Void
         */
-       function include_translation($locale, $member = FALSE)
+       function include_translation($locale)
        {
                global $DIR_LOCALES;
                
-               /* 
-                * 1. user's locale is used if set
-                * 2. system default is used if it is not empty
-                * 3. else 'en_Latn_US.ISO-8859-1.php' is included
-                *     because this translation file is expected to include only 7bit ASCII characters
-                *      which common in whole character coding scheme
-                */
-               if ( $member && $member->getLocale() )
-               {
-                       $locale = $member->getLocale();
-               }
                $translation_file = $DIR_LOCALES . $locale . '.' . i18n::get_current_charset() . '.php';
                if ( !file_exists($translation_file) )
                {
@@ -776,7 +608,7 @@ $manager->notify(
                        $translation_file = $DIR_LOCALES . 'en_Latn_US.ISO-8859-1.php';
                }
                include($translation_file);
-               return $locale;
+               return;
        }
        
        /**