Overhaul of the user authentication system
authorMarcel Werk <burntime@woltlab.com>
Fri, 12 Aug 2011 18:07:18 +0000 (20:07 +0200)
committerMarcel Werk <burntime@woltlab.com>
Fri, 12 Aug 2011 18:07:18 +0000 (20:07 +0200)
wcfsetup/install/files/lib/acp/form/LoginForm.class.php
wcfsetup/install/files/lib/system/auth/UserAuth.class.php [deleted file]
wcfsetup/install/files/lib/system/auth/UserAuthDefault.class.php [deleted file]
wcfsetup/install/files/lib/system/auth/UserAuthEmail.class.php [deleted file]
wcfsetup/install/files/lib/system/session/SessionHandler.class.php
wcfsetup/install/files/lib/system/user/authentication/AbstractUserAuthentication.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/user/authentication/DefaultUserAuthentication.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/user/authentication/EmailUserAuthentication.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/user/authentication/IUserAuthentication.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/user/authentication/UserAuthenticationFactory.class.php [new file with mode: 0644]

index 075968cfbf4cf4bd1bdcb79315cf8b84b65b5823..94e0d0134c709b99074c01a7830f8947a5e2cd53 100755 (executable)
@@ -2,7 +2,8 @@
 namespace wcf\acp\form;
 use wcf\data\user\User;
 use wcf\form\AbstractForm;
-use wcf\system\auth\UserAuth;
+use wcf\system\user\authentication\UserAuthenticationFactory;
+use wcf\system\user\authentication\EmailUserAuthentication;
 use wcf\system\exception\PermissionDeniedException;
 use wcf\system\exception\UserInputException;
 use wcf\system\WCF;
@@ -83,7 +84,26 @@ class LoginForm extends AbstractForm {
         * Validates the user access data.
         */
        protected function validateUser() {
-               $this->user = UserAuth::getInstance()->loginManually($this->username, $this->password);
+               try {
+                       $this->user = UserAuthenticationFactory::getUserAuthentication()->loginManually($this->username, $this->password);
+               }
+               catch (UserInputException $e) {
+                       // TODO: create an option for the authentication with email address
+                       if (true) {
+                               if ($e->getField() == 'username') {
+                                       try {
+                                               $this->user = EmailUserAuthentication::getInstance()->loginManually($this->username, $this->password);
+                                       }
+                                       catch (UserInputException $e2) {
+                                               if ($e->getField() == 'username') throw $e;
+                                               throw $e2;
+                                       }
+                               }
+                       }
+                       else {
+                               throw $e;
+                       }
+               }
        }
        
        /**
diff --git a/wcfsetup/install/files/lib/system/auth/UserAuth.class.php b/wcfsetup/install/files/lib/system/auth/UserAuth.class.php
deleted file mode 100644 (file)
index a4ad24f..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-namespace wcf\system\auth;
-use wcf\data\user\User;
-use wcf\system\event\EventHandler;
-
-/**
- * All user authentication types should implement the abstract functions of this class.
- * 
- * @author     Marcel Werk
- * @copyright  2001-2011 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf
- * @subpackage system.auth
- * @category   Community Framework
- */
-abstract class UserAuth {
-       /**
-        * active instance
-        * @var wcf\system\auth\UserAuth
-        */
-       protected static $instance = null;
-       
-       /**
-        * Returns an instance of the enabled user auth class.
-        * 
-        * @return      UserAuth
-        */
-       public static function getInstance() {
-               if (self::$instance === null) {
-                       // call loadInstance event
-                       EventHandler::getInstance()->fireAction(__CLASS__, 'loadInstance');
-               
-                       // use default implementation
-                       if (self::$instance === null) {
-                               self::$instance = new UserAuthDefault();
-                       }
-               }
-               
-               return self::$instance;
-       }
-       
-       /**
-        * Prevents creating an additional instance.
-        */
-       protected function __clone() {}
-       
-       /**
-        * Returns true, if this auth type supports persistent logins.
-        * 
-        * @return      boolean
-        */
-       public abstract function supportsPersistentLogins();
-       
-       /**
-        * Stores the user access data for a persistent login.
-        * 
-        * @param       User            $user
-        * @param       string          $username
-        * @param       string          $password
-        */
-       public abstract function storeAccessData(User $user, $username, $password);
-       
-       /**
-        * Does an manual user login.
-        * 
-        * @param       string          $username
-        * @param       string          $password
-        * @param       string          $userClassname          class name of user class
-        * @return      User
-        */
-       public abstract function loginManually($username, $password, $userClassname = 'wcf\data\user\User');
-       
-       /**
-        * Does an automatic user login.
-        * 
-        * @param       boolean         $persistent             true = persistent login
-        * @param       string          $userClassname          class name of user class
-        * @return      User
-        */
-       public abstract function loginAutomatically($persistent = false, $userClassname = 'wcf\data\user\User');
-}
diff --git a/wcfsetup/install/files/lib/system/auth/UserAuthDefault.class.php b/wcfsetup/install/files/lib/system/auth/UserAuthDefault.class.php
deleted file mode 100644 (file)
index 310938a..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-namespace wcf\system\auth;
-use wcf\data\user\User;
-use wcf\system\exception\UserInputException;
-use wcf\util\HeaderUtil;
-use wcf\util\StringUtil;
-
-/**
- * Default implementation of the user authentication.
- * 
- * @author     Marcel Werk
- * @copyright  2001-2011 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf
- * @subpackage system.auth
- * @category   Community Framework
- */
-class UserAuthDefault extends UserAuth {
-       /**
-        * @see wcf\system\auth\UserAuth::supportsPersistentLogins()
-        */
-       public function supportsPersistentLogins() {
-               return true;
-       }
-       
-       /**
-        * @see wcf\system\auth\UserAuth::loginManually()
-        */
-       public function loginManually($username, $password, $userClassname = 'wcf\data\user\User') {
-               $user = User::getUserByUsername($username);
-               $userSession = new $userClassname(null, null, $user);
-               
-               if ($userSession->userID == 0) {
-                       throw new UserInputException('username', 'notFound');
-               }
-       
-               // check password
-               if (!$userSession->checkPassword($password)) {
-                       throw new UserInputException('password', 'false');
-               }
-               
-               return $userSession;
-       }
-       
-       /**
-        * @see wcf\system\auth\UserAuth::storeAccessData()
-        */
-       public function storeAccessData(User $user, $username, $password) {
-               HeaderUtil::setCookie('userID', $user->userID, TIME_NOW + 365 * 24 * 3600);
-               HeaderUtil::setCookie('password', StringUtil::getSaltedHash($password, $user->salt), TIME_NOW + 365 * 24 * 3600);
-       }
-
-       /**
-        * @see wcf\system\auth\UserAuth::loginAutomatically()
-        */
-       public function loginAutomatically($persistent = false, $userClassname = 'wcf\data\user\User') {
-               if (!$persistent) return null;
-               
-               $user = null;
-               if (isset($_COOKIE[COOKIE_PREFIX.'userID']) && isset($_COOKIE[COOKIE_PREFIX.'password'])) {
-                       if (!($user = $this->getUserAutomatically(intval($_COOKIE[COOKIE_PREFIX.'userID']), $_COOKIE[COOKIE_PREFIX.'password'], $userClassname))) {
-                               $user = null;
-                               // reset cookie
-                               HeaderUtil::setCookie('userID', '');
-                               HeaderUtil::setCookie('password', '');
-                       }
-               }
-               
-               return $user;
-       }
-       
-       /**
-        * Returns a user object or null on failure.
-        * 
-        * @param       integer         $userID
-        * @param       string          $password
-        * @param       string          $userClassname
-        * @return      User    
-        */
-       protected function getUserAutomatically($userID, $password, $userClassname = 'wcf\data\user\User') {
-               $user = new $userClassname($userID);
-               if (!$user->userID || !$this->checkCookiePassword($user, $password)) {
-                       $user = null;
-               }
-               
-               return $user;
-       }
-       
-       /**
-        * Validates the cookie password.
-        * 
-        * @param       User            $user
-        * @param       string          $password
-        * @return      boolean
-        */
-       protected function checkCookiePassword($user, $password) {
-               return $user->checkCookiePassword($password);
-       }
-}
diff --git a/wcfsetup/install/files/lib/system/auth/UserAuthEmail.class.php b/wcfsetup/install/files/lib/system/auth/UserAuthEmail.class.php
deleted file mode 100644 (file)
index 4abb273..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-namespace wcf\system\auth;
-use wcf\data\user\User;
-use wcf\system\exception\UserInputException;
-use wcf\util\HeaderUtil;
-use wcf\util\StringUtil;
-
-/**
- * Implementation of the user authentication, that uses the e-mail address instead of the username to identify the user.
- * 
- * @author     Markus Bartz
- * @copyright  2011 Markus Bartz
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf
- * @subpackage system.auth
- * @category   Community Framework
- */
-class UserAuthEmail extends UserAuthDefault {
-       /**
-        * @see wcf\system\auth\UserAuth::loginManually()
-        * 
-        * In this case $username is indeed not the username, but the e-mail address.
-        */
-       public function loginManually($username, $password, $userClassname = 'wcf\data\user\User') {
-               $user = User::getUserByEmail($username);
-               $userSession = new $userClassname(null, null, $user);
-               
-               if ($userSession->userID == 0) {
-                       throw new UserInputException('username', 'notFound');
-               }
-       
-               // check password
-               if (!$userSession->checkPassword($password)) {
-                       throw new UserInputException('password', 'false');
-               }
-               
-               return $userSession;
-       }
-}
index e8416cd6341b3f0c7164e4a7adbdb435ee8b1a22..5c3d9d9387305ef823bcf1cf2d9aeb1feb571497 100644 (file)
@@ -2,9 +2,9 @@
 namespace wcf\system\session;
 use wcf\data\user\group\UserGroup;
 use wcf\data\user\User;
-use wcf\system\auth\UserAuth;
 use wcf\system\cache\CacheHandler;
 use wcf\system\exception\PermissionDeniedException;
+use wcf\system\user\authentication\UserAuthenticationFactory;
 use wcf\system\user\storage\UserStorageHandler;
 use wcf\system\SingletonFactory;
 use wcf\system\WCF;
@@ -354,7 +354,7 @@ class SessionHandler extends SingletonFactory {
                $sessionID = StringUtil::getRandomID();
                
                // get user automatically
-               $this->user = UserAuth::getInstance()->loginAutomatically();
+               $this->user = UserAuthenticationFactory::getUserAuthentication()->loginAutomatically();
                
                // create user
                if ($this->user === null) {
diff --git a/wcfsetup/install/files/lib/system/user/authentication/AbstractUserAuthentication.class.php b/wcfsetup/install/files/lib/system/user/authentication/AbstractUserAuthentication.class.php
new file mode 100644 (file)
index 0000000..d5df244
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+namespace wcf\system\user\authentication;
+use wcf\system\SingletonFactory;
+
+/**
+ * Provides an abstract implementation of the user authentication.
+ * 
+ * @author     Marcel Werk
+ * @copyright  2001-2011 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.user.authentication
+ * @category   Community Framework
+ */
+abstract class AbstractUserAuthentication extends SingletonFactory implements IUserAuthentication {}
diff --git a/wcfsetup/install/files/lib/system/user/authentication/DefaultUserAuthentication.class.php b/wcfsetup/install/files/lib/system/user/authentication/DefaultUserAuthentication.class.php
new file mode 100644 (file)
index 0000000..a91118c
--- /dev/null
@@ -0,0 +1,109 @@
+<?php
+namespace wcf\system\user\authentication;
+use wcf\data\user\User;
+use wcf\system\exception\UserInputException;
+use wcf\util\HeaderUtil;
+use wcf\util\StringUtil;
+
+/**
+ * Default implementation of the user authentication.
+ * 
+ * @author     Marcel Werk
+ * @copyright  2001-2011 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.user.authentication
+ * @category   Community Framework
+ */
+class DefaultUserAuthentication extends AbstractUserAuthentication {
+       /**
+        * @see wcf\system\user\authentication\IUserAuthentication::supportsPersistentLogins()
+        */
+       public function supportsPersistentLogins() {
+               return true;
+       }
+       
+       /**
+        * @see wcf\system\user\authentication\IUserAuthentication::storeAccessData()
+        */
+       public function storeAccessData(User $user, $username, $password) {
+               HeaderUtil::setCookie('userID', $user->userID, TIME_NOW + 365 * 24 * 3600);
+               HeaderUtil::setCookie('password', StringUtil::getSaltedHash($password, $user->salt), TIME_NOW + 365 * 24 * 3600);
+       }
+       
+       /**
+        * @see wcf\system\user\authentication\IUserAuthentication::loginManually()
+        */
+       public function loginManually($username, $password, $userClassname = 'wcf\data\user\User') {
+               $user = $this->getUserByLogin($username);
+               $userSession = (get_class($user) == $userClassname ? $user : new $userClassname(null, null, $user));
+               
+               if ($userSession->userID == 0) {
+                       throw new UserInputException('username', 'notFound');
+               }
+       
+               // check password
+               if (!$userSession->checkPassword($password)) {
+                       throw new UserInputException('password', 'false');
+               }
+               
+               return $userSession;
+       }
+       
+       /**
+        * @see wcf\system\user\authentication\IUserAuthentication::loginAutomatically()
+        */
+       public function loginAutomatically($persistent = false, $userClassname = 'wcf\data\user\User') {
+               if (!$persistent) return null;
+               
+               $user = null;
+               if (isset($_COOKIE[COOKIE_PREFIX.'userID']) && isset($_COOKIE[COOKIE_PREFIX.'password'])) {
+                       if (!($user = $this->getUserAutomatically(intval($_COOKIE[COOKIE_PREFIX.'userID']), $_COOKIE[COOKIE_PREFIX.'password'], $userClassname))) {
+                               $user = null;
+                               // reset cookie
+                               HeaderUtil::setCookie('userID', '');
+                               HeaderUtil::setCookie('password', '');
+                       }
+               }
+               
+               return $user;
+       }
+       
+       /**
+        * Returns a user object by given login name.
+        * 
+        * @param       string                  $login
+        * @return      wcf\data\user\User      
+        */
+       protected function getUserByLogin($login) {
+               return User::getUserByUsername($login);
+       }
+       
+       /**
+        * Returns a user object or null on failure.
+        * 
+        * @param       integer         $userID
+        * @param       string          $password
+        * @param       string          $userClassname
+        * @return      wcf\data\user\User      
+        */
+       protected function getUserAutomatically($userID, $password, $userClassname = 'wcf\data\user\User') {
+               $user = new $userClassname($userID);
+               if (!$user->userID || !$this->checkCookiePassword($user, $password)) {
+                       $user = null;
+               }
+               
+               return $user;
+       }
+       
+       /**
+        * Validates the cookie password.
+        * 
+        * @param       wcf\data\user\User      $user
+        * @param       string                  $password
+        * @return      boolean
+        */
+       protected function checkCookiePassword($user, $password) {
+               return $user->checkCookiePassword($password);
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/user/authentication/EmailUserAuthentication.class.php b/wcfsetup/install/files/lib/system/user/authentication/EmailUserAuthentication.class.php
new file mode 100644 (file)
index 0000000..82e628c
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+namespace wcf\system\user\authentication;
+use wcf\data\user\User;
+
+/**
+ * Implementation of the user authentication, that uses the e-mail address instead of the username to identify the user.
+ * 
+ * @author     Markus Bartz
+ * @copyright  2011 Markus Bartz
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.user.authentication
+ * @category   Community Framework
+ */
+class EmailUserAuthentication extends DefaultUserAuthentication {
+       /**
+        * @see wcf\system\user\authentication\DefaultUserAuthentication::getUserByLogin()
+        */
+       protected function getUserByLogin($login) {
+               return User::getUserByEmail($login);
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/user/authentication/IUserAuthentication.class.php b/wcfsetup/install/files/lib/system/user/authentication/IUserAuthentication.class.php
new file mode 100644 (file)
index 0000000..9ec3a0b
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+namespace wcf\system\user\authentication;
+use wcf\data\user\User;
+
+/**
+ * All user authentication types should implement this interface.
+ * 
+ * @author     Marcel Werk
+ * @copyright  2001-2011 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.user.authentication
+ * @category   Community Framework
+ */
+interface IUserAuthentication {
+       /**
+        * Returns an unique instance of the authentication class
+        * 
+        * @return      wcf\system\user\authentication\IUserAuthentication
+        */
+       public static function getInstance();
+       
+       /**
+        * Returns true, if this authentication supports persistent logins.
+        * 
+        * @return      boolean
+        */
+       public function supportsPersistentLogins();
+       
+       /**
+        * Stores the user access data for a persistent login.
+        * 
+        * @param       wcf\data\user\User      $user
+        * @param       string                  $username
+        * @param       string                  $password
+        */
+       public function storeAccessData(User $user, $username, $password);
+       
+       /**
+        * Does a manual user login.
+        * 
+        * @param       string          $username
+        * @param       string          $password
+        * @param       string          $userClassname          class name of user class
+        * @return      wcf\data\user\User
+        */
+       public function loginManually($username, $password, $userClassname = 'wcf\data\user\User');
+       
+       /**
+        * Does a user login automatically.
+        * 
+        * @param       boolean         $persistent             true = persistent login
+        * @param       string          $userClassname          class name of user class
+        * @return      wcf\data\user\User
+        */
+       public function loginAutomatically($persistent = false, $userClassname = 'wcf\data\user\User');
+}
diff --git a/wcfsetup/install/files/lib/system/user/authentication/UserAuthenticationFactory.class.php b/wcfsetup/install/files/lib/system/user/authentication/UserAuthenticationFactory.class.php
new file mode 100644 (file)
index 0000000..d8602f4
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+namespace wcf\system\user\authentication;
+use wcf\system\event\EventHandler;
+
+/**
+ * Gets the user authentication instance.
+ * 
+ * @author     Marcel Werk
+ * @copyright  2001-2011 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.user.authentication
+ * @category   Community Framework
+ */
+class UserAuthenticationFactory {
+       /**
+        * user authentication instance
+        * @var wcf\system\user\authentication\IUserAuthentication
+        */
+       protected static $userAuthentication = null;
+       
+       /**
+        * Returns user authentication instance.
+        * 
+        * @return wcf\system\user\authentication\IUserAuthentication
+        */
+       public static function getUserAuthentication() {
+               if (static::$userAuthentication === null) {
+                       // call loadInstance event
+                       EventHandler::getInstance()->fireAction(__CLASS__, 'loadUserAuthentication');
+                       
+                       // get default implementation
+                       static::loadUserAuthentication();
+               }
+               
+               return static::$userAuthentication;
+       }
+       
+       /**
+        * Loads the user authentication .
+        */
+       protected static function loadUserAuthentication() {
+               static::$userAuthentication = DefaultUserAuthentication::getInstance();
+       }
+}