From 1c3a46c869307f45e3c456254b086503600f8602 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Sat, 14 Jun 2008 19:20:03 +0000 Subject: [PATCH] Cookie-based login initially done --- .gitattributes | 4 + application/ship-simu/config.php | 6 ++ .../main/login/class_ShipSimuUserLogin.php | 18 +++- .../helper/class_ShipSimuLoginHelper.php | 73 +++++++++++++- inc/classes/interfaces/helper/.htaccess | 1 + .../interfaces/helper/class_HelpableLogin.php | 36 +++++++ .../interfaces/login/class_LoginableUser.php | 3 +- .../response/class_Responseable.php | 23 ++++- .../class_LoginAfterRegistrationAction.php | 4 +- .../main/helper/web/class_WebFormHelper.php | 3 +- inc/classes/main/login/.htaccess | 1 + inc/classes/main/login/class_CookieLogin.php | 99 +++++++++++++++++++ .../main/response/class_HttpResponse.php | 82 ++++++++++++++- inc/config.php | 15 +++ inc/config/class_FrameworkConfiguration.php | 24 ++++- templates/de/code/emergency_exit.ctp | 9 ++ 16 files changed, 387 insertions(+), 14 deletions(-) create mode 100644 inc/classes/interfaces/helper/.htaccess create mode 100644 inc/classes/interfaces/helper/class_HelpableLogin.php create mode 100644 inc/classes/main/login/.htaccess create mode 100644 inc/classes/main/login/class_CookieLogin.php diff --git a/.gitattributes b/.gitattributes index e2ffaca..81369b8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -259,6 +259,8 @@ inc/classes/interfaces/extended/.htaccess -text inc/classes/interfaces/extended/class_LimitableObject.php -text inc/classes/interfaces/filter/.htaccess -text inc/classes/interfaces/filter/class_Filterable.php -text +inc/classes/interfaces/helper/.htaccess -text +inc/classes/interfaces/helper/class_HelpableLogin.php -text inc/classes/interfaces/io/.htaccess -text inc/classes/interfaces/io/class_Streamable.php -text inc/classes/interfaces/io/file/.htaccess -text @@ -376,6 +378,8 @@ inc/classes/main/io/class_FrameworkFileInputPointer.php -text inc/classes/main/io/class_FrameworkFileOutputPointer.php -text inc/classes/main/language/.htaccess -text inc/classes/main/language/class_LanguageSystem.php -text +inc/classes/main/login/.htaccess -text +inc/classes/main/login/class_CookieLogin.php -text inc/classes/main/output/.htaccess -text inc/classes/main/output/class_ConsoleOutput.php -text inc/classes/main/output/class_WebOutput.php -text diff --git a/application/ship-simu/config.php b/application/ship-simu/config.php index 3d4b877..a827e38 100644 --- a/application/ship-simu/config.php +++ b/application/ship-simu/config.php @@ -82,5 +82,11 @@ $cfg->setConfigEntry('user_status_register', "UNCONFIRMED"); // CFG: LOGIN-HELPER $cfg->setConfigEntry('login_helper', "ShipSimuLoginHelper"); +// CFG: LOGIN-METHOD +$cfg->setConfigEntry('login_method', "cookie"); + +// CFG: APP-LOGIN-URL +$cfg->setConfigEntry('app_login_url', "index.php?app=ship-simu&page=login_area"); + // [EOF] ?> diff --git a/application/ship-simu/main/login/class_ShipSimuUserLogin.php b/application/ship-simu/main/login/class_ShipSimuUserLogin.php index a043de8..59ddcdc 100644 --- a/application/ship-simu/main/login/class_ShipSimuUserLogin.php +++ b/application/ship-simu/main/login/class_ShipSimuUserLogin.php @@ -61,6 +61,7 @@ class ShipSimuUserLogin extends BaseFrameworkSystem implements LoginableUser { * in a boolean attribute which is then readable by a matching getter. * * @param $requestInstance An instance of a Requestable class + * @param $responseInstance An instance of a Responseable class * @return void * @throws UserLoginMethodException If wether username nor email login * was detected @@ -69,7 +70,7 @@ class ShipSimuUserLogin extends BaseFrameworkSystem implements LoginableUser { * @throws UserPasswordMismatchException If the supplied password did not * match with the stored password */ - public function doLogin (Requestable $requestInstance) { + public function doLogin (Requestable $requestInstance, Responseable $responseInstance) { // By default no method is selected $method = null; $data = ""; @@ -118,7 +119,20 @@ class ShipSimuUserLogin extends BaseFrameworkSystem implements LoginableUser { $helperInstance = ObjectFactory::createObjectByConfiguredName('login_helper', array($requestInstance)); // 2) Execute the login. This will now login... - $helperInstance->executeLogin(); + $helperInstance->executeLogin($responseInstance); + } + + /** + * Determines wether the login was fine. This is done by checking if the 'login' instance is in registry + * + * @return $loginDone Wether the login was fine or not + */ + public function ifLoginWasSuccessfull () { + // Is the registry key there? + $loginDone = (Registry::getRegistry()->getInstance('login') instanceof Registerable); + + // Return the result + return $loginDone; } } diff --git a/application/ship-simu/main/login/helper/class_ShipSimuLoginHelper.php b/application/ship-simu/main/login/helper/class_ShipSimuLoginHelper.php index 13bed29..9dd7f96 100644 --- a/application/ship-simu/main/login/helper/class_ShipSimuLoginHelper.php +++ b/application/ship-simu/main/login/helper/class_ShipSimuLoginHelper.php @@ -15,7 +15,6 @@ * @copyright Copyright(c) 2007, 2008 Roland Haeder, this is free software * @license GNU GPL 3.0 or any newer version * @link http://www.ship-simu.org - * @todo Find an interface name for login helper * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +29,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -class ShipSimuLoginHelper extends BaseLoginHelper { +class ShipSimuLoginHelper extends BaseLoginHelper implements HelpableLogin { + /** + * The login method we shall choose + */ + private $loginMethod = ""; + + /** + * Instance for a request class + */ + private $requestInstance = null; + // Exception constants const EXCEPTION_INVALID_USER_INSTANCE = 0xf00; @@ -88,11 +97,67 @@ class ShipSimuLoginHelper extends BaseLoginHelper { // Set default login method from config $helperInstance->setDefaultLoginMethod(); } - + + // Set request instance + $helperInstance->setRequestInstance($requestInstance); + // Return the prepared instance return $helperInstance; } + + /** + * Setter for default login method from config + * + * @return void + */ + protected function setDefaultLoginMethod () { + $this->loginMethod = $this->getConfigInstance()->readConfig('login_method'); + } + + /** + * Setter for request instance + * + * @param $requestInstance A Requestable class instance + * @return void + */ + public final function setRequestInstance (Requestable $requestInstance) { + $this->requestInstance = $requestInstance; + } + + /** + * Getter for request instance + * + * @param + * @return $requestInstance A Requestable class instance + */ + public final function getRequestInstance () { + return $this->requestInstance; + } + + /** + * Execute the login request by given response instance. This instance can + * be used for sending cookies or at least the session id out. + * + * @param $responseInstance An instance of a Responseable class + * @return void + */ + public function executeLogin (Responseable $responseInstance) { + // First create the requested login method name + $loginMethodClass = ucfirst(strtolower($this->loginMethod)) . "Login"; + + // Then try to get an instance from it + $loginInstance = ObjectFactory::createObjectByName($loginMethodClass, array($responseInstance)); + + // Set user cookie + $loginInstance->setUserAuth($this->requestInstance->getRequestElement('username')); + + // Set password cookie + $loginInstance->setPasswordAuth($this->requestInstance->getRequestElement('pass_hash')); + + // Remember this login instance for later usage + Registry::getRegistry()->addInstance('login', $loginInstance); + } } -// [EOF] +// ?> diff --git a/inc/classes/interfaces/helper/.htaccess b/inc/classes/interfaces/helper/.htaccess new file mode 100644 index 0000000..3a42882 --- /dev/null +++ b/inc/classes/interfaces/helper/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/inc/classes/interfaces/helper/class_HelpableLogin.php b/inc/classes/interfaces/helper/class_HelpableLogin.php new file mode 100644 index 0000000..cf5f84f --- /dev/null +++ b/inc/classes/interfaces/helper/class_HelpableLogin.php @@ -0,0 +1,36 @@ + + * @version 0.0.0 + * @copyright Copyright(c) 2007, 2008 Roland Haeder, this is free software + * @license GNU GPL 3.0 or any newer version + * @link http://www.ship-simu.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +interface HelpableLogin extends FrameworkInterface { + /** + * Execute the login request by given response instance. This instance can + * be used for sending cookies or at least the session id out. + * + * @param $responseInstance An instance of a Responseable class + * @return void + */ + function executeLogin (Responseable $responseInstance); +} + +// +?> diff --git a/inc/classes/interfaces/login/class_LoginableUser.php b/inc/classes/interfaces/login/class_LoginableUser.php index 962cba8..107b133 100644 --- a/inc/classes/interfaces/login/class_LoginableUser.php +++ b/inc/classes/interfaces/login/class_LoginableUser.php @@ -28,9 +28,10 @@ interface LoginableUser extends FrameworkInterface { * in a boolean attribute which is then readable by a matching getter. * * @param $requestInstance An instance of a Requestable class + * @param $responseInstance An instance of a Responseable class * @return void */ - function doLogin (Requestable $requestInstance); + function doLogin (Requestable $requestInstance, Responseable $responseInstance); } // diff --git a/inc/classes/interfaces/response/class_Responseable.php b/inc/classes/interfaces/response/class_Responseable.php index c7d2103..5fd6b50 100644 --- a/inc/classes/interfaces/response/class_Responseable.php +++ b/inc/classes/interfaces/response/class_Responseable.php @@ -56,7 +56,7 @@ interface Responseable extends FrameworkInterface { * @throws ResponseHeadersAlreadySentException Thrown if headers are * already sent */ - function flushBuffer($force=false); + function flushBuffer ($force = false); /** * Adds a fatal message id to the response. The added messages can then be @@ -66,6 +66,27 @@ interface Responseable extends FrameworkInterface { * @return void */ function addFatalMessage ($messageId); + + /** + * Adds a cookie to the response + * + * @param $cookieName Cookie's name + * @param $cookieValue Value to store in the cookie + * @param $encrypted Do some extra encryption on the value + * @return void + * @throws ResponseHeadersAlreadySentException If headers are already sent + */ + function addCookie ($cookieName, $cookieValue, $encrypted = false); + + /** + * Redirect to a configured URL. The URL can be absolute or relative. In + * case of relative URL it will be extended automatically. + * + * @param $configEntry The configuration entry which holds our URL + * @return void + * @throws ResponseHeadersAlreadySentException If headers are already sent + */ + function redirectToConfiguredUrl ($configEntry); } // diff --git a/inc/classes/main/actions/post_registration/class_LoginAfterRegistrationAction.php b/inc/classes/main/actions/post_registration/class_LoginAfterRegistrationAction.php index aae33eb..63c4450 100644 --- a/inc/classes/main/actions/post_registration/class_LoginAfterRegistrationAction.php +++ b/inc/classes/main/actions/post_registration/class_LoginAfterRegistrationAction.php @@ -63,13 +63,13 @@ class LoginAfterRegistrationAction extends BaseAction implements Commandable { $loginInstance = ObjectFactory::createObjectByConfiguredName('login_user'); // Login the user by the request instance - $loginInstance->doLogin($requestInstance); + $loginInstance->doLogin($requestInstance, $responseInstance); // Was the login fine? Then redirect here if ($loginInstance->ifLoginWasSuccessfull()) { // Try to redirect here try { - $responseInstance->redirectConfiguredUrl('app_login'); + $responseInstance->redirectToConfiguredUrl('app_login_url'); } catch (FrameworkException $e) { // Something went wrong here! $responseInstance->addFatalMessage($e->getMessage()); diff --git a/inc/classes/main/helper/web/class_WebFormHelper.php b/inc/classes/main/helper/web/class_WebFormHelper.php index e71f151..718ed77 100644 --- a/inc/classes/main/helper/web/class_WebFormHelper.php +++ b/inc/classes/main/helper/web/class_WebFormHelper.php @@ -119,8 +119,9 @@ class WebFormHelper extends BaseHelper { // Check wether we shall open or close the form if ($this->formOpened === false) { // Add HTML code - $formContent = sprintf("
getConfigInstance()->readConfig('base_url'), $this->getConfigInstance()->readConfig('form_action'), $this->getConfigInstance()->readConfig('form_method'), $this->getConfigInstance()->readConfig('form_target') diff --git a/inc/classes/main/login/.htaccess b/inc/classes/main/login/.htaccess new file mode 100644 index 0000000..3a42882 --- /dev/null +++ b/inc/classes/main/login/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/inc/classes/main/login/class_CookieLogin.php b/inc/classes/main/login/class_CookieLogin.php new file mode 100644 index 0000000..cbc9203 --- /dev/null +++ b/inc/classes/main/login/class_CookieLogin.php @@ -0,0 +1,99 @@ + + * @version 0.0.0 + * @copyright Copyright(c) 2007, 2008 Roland Haeder, this is free software + * @license GNU GPL 3.0 or any newer version + * @link http://www.ship-simu.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +class CookieLogin extends BaseFrameworkSystem implements Registerable { + /** + * Response instance + */ + private $responseInstance = null; + + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + + // Set part description + $this->setObjectDescription("Cookie-based login"); + + // Create unique ID number + $this->generateUniqueId(); + + // Clean up a little + $this->removeNumberFormaters(); + $this->removeSystemArray(); + } + + /** + * Creates an instance of this class by the given response instance + * + * @param $responseInstance An instance of a Responseable class + * @return $loginInstance An instance of this login class + */ + public final static function createCookieLogin (Responseable $responseInstance) { + // Get a new instance + $loginInstance = new CookieLogin(); + + // Set the response instance + $loginInstance->setResponseInstance($responseInstance); + + // Return the prepared instance + return $loginInstance; + } + + /** + * Setter for login instance + * + * @param $responseInstance An instance of a Responseable class + * @return void + */ + protected final function setResponseInstance (Responseable $responseInstance) { + $this->responseInstance = $responseInstance; + } + + /** + * "Setter" for username auth data + * + * @param $userName The username from request we shall set + * @return void + */ + public function setUserAuth ($userName) { + $this->responseInstance->addCookie('username', $userName); + } + + /** + * "Setter" for password hash auth data + * + * @param $passHash The hashed password from request we shall set + * @return void + */ + public function setPasswordAuth ($passHash) { + $this->responseInstance->addCookie('u_hash', $passHash, true); + } +} + +// [EOF] +?> diff --git a/inc/classes/main/response/class_HttpResponse.php b/inc/classes/main/response/class_HttpResponse.php index 074373d..bc76933 100644 --- a/inc/classes/main/response/class_HttpResponse.php +++ b/inc/classes/main/response/class_HttpResponse.php @@ -136,7 +136,7 @@ class HttpResponse extends BaseFrameworkSystem implements Responseable { * @param $output Output we shall sent in the HTTP response * @return void */ - public function setReponseBody ($output) { + public function setResponseBody ($output) { $this->responseBody = $output; } @@ -187,7 +187,7 @@ class HttpResponse extends BaseFrameworkSystem implements Responseable { } // Clear response header and body - $this->setReponseBody(""); + $this->setResponseBody(""); $this->resetResponseHeaders(); } @@ -221,6 +221,84 @@ class HttpResponse extends BaseFrameworkSystem implements Responseable { // Adds the resolved message id to the fatal message list $this->fatalMessages[] = $this->getApplicationInstance()->getLanguageInstance()->getMessage($messageId); } + + /** + * Adds a cookie to the response + * + * @param $cookieName Cookie's name + * @param $cookieValue Value to store in the cookie + * @param $encrypted Do some extra encryption on the value + * @return void + * @throws ResponseHeadersAlreadySentException If headers are already sent + */ + public function addCookie ($cookieName, $cookieValue, $encrypted = false) { + // Are headers already sent? + if (headers_sent()) { + // Throw an exception here + throw new ResponseHeadersAlreadySentException($this, self::EXCEPTION_HEADERS_ALREADY_SENT); + } // END - if + + // Shall we encrypt the cookie? + if ($encrypted === true) { + // @TODO Encryption of cookie data not yet supported + } // END - if + + // Set the cookie + setcookie( + $cookieName, + $cookieValue, + $this->getConfigInstance()->readConfig('cookie_expire'), + $this->getConfigInstance()->readConfig('cookie_path'), + $this->getConfigInstance()->readConfig('cookie_domain'), + $this->getConfigInstance()->readConfig('cookie_ssl') + ); + } + + /** + * Redirect to a configured URL. The URL can be absolute or relative. In + * case of relative URL it will be extended automatically. + * + * @param $configEntry The configuration entry which holds our URL + * @return void + * @throws ResponseHeadersAlreadySentException If headers are already sent + */ + public function redirectToConfiguredUrl ($configEntry) { + // Is the header not yet sent? + if (headers_sent()) { + // Throw an exception here + throw new ResponseHeadersAlreadySentException($this, self::EXCEPTION_HEADERS_ALREADY_SENT); + } // END - if + + // Get the url from config + $url = $this->getConfigInstance()->readConfig($configEntry); + + // Do we have a "http" in front of the URL? + if (substr(strtolower($url), 0, 4) != "http") { + // Is there a / in front of the relative URL? + if (substr($url, 0, 1) == "/") $url = substr($url, 1); + + // No, then extend it with our base URL + $url = $this->getConfigInstance()->readConfig('base_url') . "/" . $url; + } // END - if + + // Clean response headers + $this->resetResponseHeaders(); + + // Add redirect header + $this->addHeader("Location", $url); + + // Set correct response status + $this->setResponseStatus("301 Moved Permanently"); + + // Clear the body + $this->setResponseBody(""); + + // Flush the result + $this->flushBuffer(); + + // All done here... + exit(); + } } // [EOF] diff --git a/inc/config.php b/inc/config.php index 0b450d8..817609c 100644 --- a/inc/config.php +++ b/inc/config.php @@ -35,6 +35,9 @@ $cfg = FrameworkConfiguration::createFrameworkConfiguration(); // CFG: SERVER-PATH $cfg->definePath(dirname(dirname(__FILE__)) . '/'); // DON'T MISS THE TRAILING SLASH!!! +// CFG: BASE-URL +$cfg->setConfigEntry('base_url', $cfg->detectBaseUrl()); + // CFG: DATABASE-TYPE $cfg->defineDatabaseType('local'); @@ -218,5 +221,17 @@ $cfg->setConfigEntry('post_registration_action', "LoginAfterRegistrationAction") // CFG: USER-CLASS $cfg->setConfigEntry('user_class', "User"); +// CFG: COOKIE-EXPIRE +$cfg->setConfigEntry('cookie_expire', 60*60*24*2); // Two hours! + +// CFG: COOKIE-PATH +$cfg->setConfigEntry('cookie_path', dirname($_SERVER['SCRIPT_NAME']) . "/"); + +// CFG: COOKIE-DOMAIN +$cfg->setConfigEntry('cookie_domain', $cfg->readConfig('base_url')); // Is mostly the same... + +// CFG: COOKIE-SSL +$cfg->setConfigEntry('cookie_ssl', (isset($_SERVER['HTTPS']))); + // [EOF] ?> diff --git a/inc/config/class_FrameworkConfiguration.php b/inc/config/class_FrameworkConfiguration.php index 6bfc3a2..5e9b87e 100644 --- a/inc/config/class_FrameworkConfiguration.php +++ b/inc/config/class_FrameworkConfiguration.php @@ -169,7 +169,7 @@ class FrameworkConfiguration implements Registerable { /** * Define the local file path * - * @param $path The database type. See path inc/database/. + * @param $path Local file path for include files. * @return void */ public function definePath ($path) { @@ -261,6 +261,28 @@ class FrameworkConfiguration implements Registerable { public function __toString () { return get_class($this); } + + /** + * Dectect and return the base URL for all URLs and forms + * + * @return $baseUrl Detected base URL + */ + public function detectBaseUrl() { + // Initialize the URL + $baseUrl = "http"; + + // Do we have HTTPS? + if (isset($_SERVER['HTTPS'])) { + // Add the >s< for HTTPS + $baseUrl .= "s"; + } // END - if + + // Construct the full URL now and secure it against CSRF attacks + $baseUrl = $baseUrl . "://" . htmlentities(strip_tags($_SERVER['SERVER_NAME']), ENT_QUOTES) . dirname($_SERVER['SCRIPT_NAME']); + + // Return the URL + return $baseUrl; + } } // END - class // [EOF] diff --git a/templates/de/code/emergency_exit.ctp b/templates/de/code/emergency_exit.ctp index d5c6f90..29725af 100644 --- a/templates/de/code/emergency_exit.ctp +++ b/templates/de/code/emergency_exit.ctp @@ -17,4 +17,13 @@ +
+
+ Statistics +
+
+ Total objects: $content[total_objects] +
+
+ {?footer_msg:footer_msg="Please contact the support and supply the full above message, if you think you are not qualified to fix this problem."?} -- 2.39.2