[FEATURE] Separate password transmission from password comparison
authorHelmut Hummel <helmut.hummel@typo3.org>
Sun, 21 Aug 2011 21:56:12 +0000 (23:56 +0200)
committerOliver Hader <oliver@typo3.org>
Tue, 17 Jan 2012 14:28:04 +0000 (15:28 +0100)
Add a processing authorization service to be able to treat (decrypt, hash)
passwords transmitted for other services that then can only compare the credentials.

Resolves: #30271
Releases: 4.7

Change-Id: Ic8ebeaa58d1cc1662083b0799f670b5a79e43971
Reviewed-on: http://review.typo3.org/5326
Reviewed-by: Steffen Ritter
Tested-by: Steffen Ritter
Reviewed-by: Oliver Hader
Tested-by: Oliver Hader
12 files changed:
t3lib/class.t3lib_beuserauth.php
t3lib/class.t3lib_tsfebeuserauth.php
t3lib/class.t3lib_userauth.php
tests/t3lib/class.t3lib_userauthTest.php [new file with mode: 0644]
typo3/sysext/rsaauth/ext_localconf.php
typo3/sysext/rsaauth/hooks/class.tx_rsaauth_feloginhook.php
typo3/sysext/rsaauth/hooks/class.tx_rsaauth_usersetuphook.php
typo3/sysext/rsaauth/sv1/class.tx_rsaauth_sv1.php
typo3/sysext/saltedpasswords/sv1/class.tx_saltedpasswords_sv1.php
typo3/sysext/sv/class.tx_sv_auth.php
typo3/sysext/sv/class.tx_sv_authbase.php
typo3/sysext/sv/ext_localconf.php

index 777b0a7..3aa5dc4 100644 (file)
@@ -140,14 +140,11 @@ class t3lib_beUserAuth extends t3lib_userAuthGroup {
                $securityLevel = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel']);
                $standardSecurityLevels = array('normal', 'challenged', 'superchallenged');
 
-                       // No challenge is stored in the session if security level is normal
-               if ($securityLevel === 'normal') {
-                       $this->challengeStoredInCookie = FALSE;
-               }
-
                        // The TYPO3 standard login service relies on $this->security_level being set
-                       // to 'superchallenged' because of the password in the database is stored as md5 hash
-                       // @see t3lib_userauth::processLoginData()
+                       // to 'superchallenged' because of the password in the database is stored as md5 hash.
+                       // @deprecated since 4.7
+                       // These lines are here for compatibility purpose only, can be removed in 4.9.
+                       // @see tx_sv_auth::processLoginData()
                if (!empty($securityLevel) && !in_array($securityLevel, $standardSecurityLevels)) {
                        $this->security_level = $securityLevel;
                } else {
@@ -408,4 +405,4 @@ if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLA
        include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_beuserauth.php']);
 }
 
-?>
\ No newline at end of file
+?>
index 99ab819..823738e 100644 (file)
@@ -69,6 +69,7 @@ class t3lib_tsfeBeUserAuth extends t3lib_beUserAuth {
         * from form in $formfield_uident. 'superchallenged' = hashed password hashed again with username.
         *
         * @var string
+        * @deprecated since 4.7 will be removed in 4.9
         */
        public $security_level = '';
 
index 2b89e96..6222fd7 100644 (file)
@@ -74,7 +74,15 @@ abstract class t3lib_userAuth {
        var $formfield_uident = ''; // formfield with password
        var $formfield_chalvalue = ''; // formfield with a unique value which is used to encrypt the password and username
        var $formfield_status = ''; // formfield with status: *'login', 'logout'. If empty login is not verified.
-       var $security_level = 'normal'; // sets the level of security. *'normal' = clear-text. 'challenged' = hashed password/username from form in $formfield_uident. 'superchallenged' = hashed password hashed again with username.
+
+       /**
+        * Sets the level of security. *'normal' = clear-text. 'challenged' = hashed password/username.
+        * from form in $formfield_uident. 'superchallenged' = hashed password hashed again with username.
+        *
+        * @var string
+        * @deprecated since 4.7 will be removed in 4.9
+        */
+       public $security_level = 'normal';
 
        var $auth_timeout_field = 0; // Server session lifetime. If > 0: session-timeout in seconds. If FALSE or <0: no timeout. If string: The string is a fieldname from the usertable where the timeout can be found.
        var $lifetime = 0; // Client session lifetime. 0 = Session-cookies. If session-cookies, the browser will stop the session when the browser is closed. Otherwise this specifies the lifetime of a cookie that keeps the session.
@@ -1152,42 +1160,48 @@ abstract class t3lib_userAuth {
 
        /**
         * Processes Login data submitted by a form or params depending on the
-        * security_level
+        * passwordTransmissionStrategy
         *
         * @param       array           login data array
-        * @param       string          Alternative security_level. Used when authentication services wants to override the default.
+        * @param       string          Alternative passwordTransmissionStrategy. Used when authentication services wants to override the default.
         * @return      array           processed login data array
         * @internal
         */
-       function processLoginData($loginData, $security_level = '') {
-               $loginSecurityLevel = $security_level ? $security_level : ($GLOBALS['TYPO3_CONF_VARS'][$this->loginType]['loginSecurityLevel'] ? $GLOBALS['TYPO3_CONF_VARS'][$this->loginType]['loginSecurityLevel'] : $this->security_level);
-
-                       // Processing data according to the state it was submitted in.
-                       // ($loginSecurityLevel should reflect the security level used on the data being submitted in the login form)
-               if ($loginSecurityLevel == 'normal') {
-                       $loginData['uident_text'] = $loginData['uident'];
-                       $loginData['uident_challenged'] = (string) md5($loginData['uname'] . ':' . $loginData['uident'] . ':' . $loginData['chalvalue']);
-                       $loginData['uident_superchallenged'] = (string) md5($loginData['uname'] . ':' . (md5($loginData['uident'])) . ':' . $loginData['chalvalue']);
-               } elseif ($loginSecurityLevel == 'challenged') {
-                       $loginData['uident_text'] = '';
-                       $loginData['uident_challenged'] = $loginData['uident'];
-                       $loginData['uident_superchallenged'] = '';
-               } elseif ($loginSecurityLevel == 'superchallenged') {
-                       $loginData['uident_text'] = '';
-                       $loginData['uident_challenged'] = '';
-                       $loginData['uident_superchallenged'] = $loginData['uident'];
+       function processLoginData($loginData, $passwordTransmissionStrategy = '') {
+               $passwordTransmissionStrategy = $passwordTransmissionStrategy ? $passwordTransmissionStrategy : ($GLOBALS['TYPO3_CONF_VARS'][$this->loginType]['loginSecurityLevel'] ? trim($GLOBALS['TYPO3_CONF_VARS'][$this->loginType]['loginSecurityLevel']) : $this->security_level);
+
+               if ($this->writeDevLog) {
+                       t3lib_div::devLog('Login data before processing: ' . t3lib_div::arrayToLogString($loginData), 't3lib_userAuth');
                }
 
-                       // The password "uident" is set based on the internal security setting of TYPO3
-                       // Example:
-                       // $this->security_level for the backend must be "superchallenged" because passwords are stored as md5-hashes in the be_users table
-                       // $this->security_level for the frontend must be "normal" or "challenged" because passwords are stored as clear-text in the fe_users tables
-               if ($this->security_level == 'normal') {
-                       $loginData['uident'] = $loginData['uident_text'];
-               } elseif ($this->security_level == 'challenged') {
-                       $loginData['uident'] = $loginData['uident_challenged'];
-               } elseif ($this->security_level == 'superchallenged') {
-                       $loginData['uident'] = $loginData['uident_superchallenged'];
+               $serviceChain = '';
+               $subType = 'processLoginData' . $this->loginType;
+               $authInfo = $this->getAuthInfoArray();
+               $isLoginDataProcessed = FALSE;
+               $processedLoginData = $loginData;
+               while (is_object($serviceObject = t3lib_div::makeInstanceService('auth', $subType, $serviceChain))) {
+                       $serviceChain .= ',' . $serviceObject->getServiceKey();
+                       $serviceObject->initAuth($subType, $loginData, $authInfo, $this);
+
+                       $serviceResult = $serviceObject->processLoginData($processedLoginData, $passwordTransmissionStrategy);
+
+                       if (!empty($serviceResult)) {
+                               $isLoginDataProcessed = TRUE;
+
+                                       // if the service returns >=200 then no more processing is needed
+                               if (intval($serviceResult) >= 200)      {
+                                       unset($serviceObject);
+                                       break;
+                               }
+                       }
+                       unset($serviceObject);
+               }
+
+               if ($isLoginDataProcessed) {
+                       $loginData = $processedLoginData;
+                       if ($this->writeDevLog) {
+                               t3lib_div::devLog('Processed login data: '.t3lib_div::arrayToLogString($processedLoginData), 't3lib_userAuth');
+                       }
                }
 
                return $loginData;
@@ -1206,6 +1220,7 @@ abstract class t3lib_userAuth {
                $authInfo['HTTP_HOST'] = t3lib_div::getIndpEnv('HTTP_HOST');
                $authInfo['REMOTE_ADDR'] = t3lib_div::getIndpEnv('REMOTE_ADDR');
                $authInfo['REMOTE_HOST'] = t3lib_div::getIndpEnv('REMOTE_HOST');
+               /** @deprecated the usage of $authInfo['security_level'] is deprecated since 4.7 */
                $authInfo['security_level'] = $this->security_level;
                $authInfo['showHiddenRecords'] = $this->showHiddenRecords;
                        // can be overidden in localconf by SVCONF:
@@ -1226,15 +1241,15 @@ abstract class t3lib_userAuth {
         *
         * @param       array           user data array
         * @param       array           login data array
-        * @param       string          Alternative security_level. Used when authentication services wants to override the default.
+        * @param       string          Alternative passwordCompareStrategy. Used when authentication services wants to override the default.
         * @return      boolean         TRUE if login data matched
         */
-       function compareUident($user, $loginData, $security_level = '') {
+       function compareUident($user, $loginData, $passwordCompareStrategy = '') {
 
                $OK = FALSE;
-               $security_level = $security_level ? $security_level : $this->security_level;
+               $passwordCompareStrategy = $passwordCompareStrategy ? $passwordCompareStrategy : $this->security_level;
 
-               switch ($security_level) {
+               switch ($passwordCompareStrategy) {
                        case 'superchallenged': // If superchallenged the password in the database ($user[$this->userident_column]) must be a md5-hash of the original password.
                        case 'challenged':
 
@@ -1250,12 +1265,12 @@ abstract class t3lib_userAuth {
                                        }
                                }
 
-                               if ((string) $loginData['uident'] === (string) md5($user[$this->username_column] . ':' . $user[$this->userident_column] . ':' . $loginData['chalvalue'])) {
+                               if ((string) $loginData['uident_' . $passwordCompareStrategy] === (string) md5($user[$this->username_column] . ':' . $user[$this->userident_column] . ':' . $loginData['chalvalue'])) {
                                        $OK = TRUE;
                                }
                        break;
                        default: // normal
-                               if ((string) $loginData['uident'] === (string) $user[$this->userident_column]) {
+                               if ((string) $loginData['uident_text'] === (string) $user[$this->userident_column]) {
                                        $OK = TRUE;
                                }
                        break;
diff --git a/tests/t3lib/class.t3lib_userauthTest.php b/tests/t3lib/class.t3lib_userauthTest.php
new file mode 100644 (file)
index 0000000..820f87f
--- /dev/null
@@ -0,0 +1,183 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Helmut Hummel <helmut.hummel@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project 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 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script 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.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Testcase for class t3lib_userauth
+ *
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_userauthTest extends tx_phpunit_testcase {
+
+       /**
+        * Enable backup of global and system variables
+        *
+        * @var boolean
+        */
+       protected $backupGlobals = TRUE;
+
+       /**
+        * Exclude TYPO3_DB from backup/ restore of $GLOBALS
+        * because resource types cannot be handled during serializing
+        *
+        * @var array
+        */
+       protected $backupGlobalsBlacklist = array('TYPO3_DB');
+
+       /**
+        * phpunit still needs some globals that are
+        * reconstructed before $backupGlobals is handled. Those
+        * important globals are handled in tearDown() directly.
+        *
+        * @var array
+        */
+       protected $globals = array();
+
+       public function setUp() {
+               $this->globals = array(
+                       'TYPO3_LOADED_EXT' => serialize($GLOBALS['TYPO3_LOADED_EXT']),
+               );
+       }
+
+       public function tearDown() {
+               foreach ($this->globals as $key => $value) {
+                       $GLOBALS[$key] = unserialize($value);
+               }
+       }
+
+       ////////////////////////////////////
+       // Tests concerning processLoginData
+       ////////////////////////////////////
+
+
+       public function processLoginDataProvider() {
+               return array(
+
+                       'Backend login with securityLevel "normal"' => array(
+                               'BE',
+                               'normal',
+                               'superchallenged',
+                               array (
+                                       'status' =>  'login',
+                                       'uname' =>  'admin',
+                                       'uident' =>  'password',
+                                       'chalvalue' =>  NULL,
+                               ),
+                               array (
+                                       'status' =>  'login',
+                                       'uname' =>  'admin',
+                                       'uident' =>  '651219fccfbe0c9004c7196515d780ce',
+                                       'chalvalue' =>  NULL,
+                                       'uident_text' =>  'password',
+                                       'uident_challenged' =>  '458203772635d38f05ca9e62d8237974',
+                                       'uident_superchallenged' =>  '651219fccfbe0c9004c7196515d780ce',
+                               ),
+                       ),
+
+                       'Backend login with securityLevel "superchallenged"' => array(
+                               'BE',
+                               'superchallenged',
+                               'superchallenged',
+                               array (
+                                       'status' =>  'login',
+                                       'uname' =>  'admin',
+                                       'uident' =>  '651219fccfbe0c9004c7196515d780ce',
+                                       'chalvalue' =>  NULL,
+                               ),
+                               array (
+                                       'status' =>  'login',
+                                       'uname' =>  'admin',
+                                       'uident' =>  '651219fccfbe0c9004c7196515d780ce',
+                                       'chalvalue' =>  NULL,
+                                       'uident_text' =>  '',
+                                       'uident_challenged' =>  '',
+                                       'uident_superchallenged' =>  '651219fccfbe0c9004c7196515d780ce',
+                               ),
+                       ),
+
+                       'Frontend login with securityLevel "normal"' => array(
+                               'FE',
+                               'normal',
+                               'normal',
+                               array (
+                                       'status' =>  'login',
+                                       'uname' =>  'admin',
+                                       'uident' =>  'password',
+                                       'chalvalue' =>  NULL,
+                               ),
+                               array (
+                                       'status' =>  'login',
+                                       'uname' =>  'admin',
+                                       'uident' =>  'password',
+                                       'chalvalue' =>  NULL,
+                                       'uident_text' =>  'password',
+                                       'uident_challenged' =>  '458203772635d38f05ca9e62d8237974',
+                                       'uident_superchallenged' =>  '651219fccfbe0c9004c7196515d780ce',
+                               ),
+                       ),
+
+                       'Frontend login with securityLevel "challenged"' => array(
+                               'FE',
+                               'challenged',
+                               'challenged',
+                               array (
+                                       'status' =>  'login',
+                                       'uname' =>  'admin',
+                                       'uident' =>  '458203772635d38f05ca9e62d8237974',
+                                       'chalvalue' =>  NULL,
+                               ),
+                               array (
+                                       'status' =>  'login',
+                                       'uname' =>  'admin',
+                                       'uident' =>  '458203772635d38f05ca9e62d8237974',
+                                       'chalvalue' =>  NULL,
+                                       'uident_text' =>  '',
+                                       'uident_challenged' =>  '458203772635d38f05ca9e62d8237974',
+                                       'uident_superchallenged' =>  '',
+                               ),
+                       ),
+
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider processLoginDataProvider
+        */
+       public function processLoginReturnsCorrectData($loginType, $passwordSubmissionStrategy, $passwordCompareStrategy, $originalData, $processedData) {
+
+               /** @var $mock t3lib_userauth */
+               $mock = $this->getMock('t3lib_userauth', array('_dummy'));
+               $mock->security_level = $passwordCompareStrategy;
+               $mock->loginType = $loginType;
+
+               $this->assertEquals($mock->processLoginData($originalData, $passwordSubmissionStrategy), $processedData);
+
+       }
+}
+
+
+
+
+?>
\ No newline at end of file
index f3168f7..2cc323e 100644 (file)
@@ -9,7 +9,7 @@ t3lib_extMgm::addService($_EXTKEY,  'auth' /* sv type */,  'tx_rsaauth_sv1' /* s
                'title' => 'RSA authentication',
                'description' => 'Authenticates users by using encrypted passwords',
 
-               'subtype' => 'getUserBE,authUserBE,getUserFE,authUserFE',
+               'subtype' => 'processLoginDataBE,processLoginDataFE',
 
                'available' => TRUE,
                'priority' => 60,       // tx_svauth_sv1 has 50, t3sec_saltedpw has 55. This service must have higher priority!
index 5823ddf..04fc2b6 100644 (file)
@@ -41,7 +41,7 @@ class tx_rsaauth_feloginhook {
        public function loginFormHook() {
                $result = array(0 => '', 1 => '');
 
-               if ($GLOBALS['TYPO3_CONF_VARS']['FE']['loginSecurityLevel'] == 'rsa') {
+               if (trim($GLOBALS['TYPO3_CONF_VARS']['FE']['loginSecurityLevel']) === 'rsa') {
                        $backend = tx_rsaauth_backendfactory::getBackend();
                        if ($backend) {
                                $result[0] = 'tx_rsaauth_feencrypt(this);';
index abf205c..de9e864 100644 (file)
@@ -110,12 +110,12 @@ class tx_rsaauth_usersetuphook {
        }
 
        /**
-        * Rsa is available if security_level is set and rsa backend is working.
+        * Rsa is available if loginSecurityLevel is set and rsa backend is working.
         *
         * @return bool
         */
        protected function isRsaAvailable() {
-               return ($GLOBALS['BE_USER']->security_level === 'rsa') && (tx_rsaauth_backendfactory::getBackend() !== NULL);
+               return (trim($GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel']) === 'rsa') && (tx_rsaauth_backendfactory::getBackend() !== NULL);
        }
 
 
index 8f8c858..59ffd89 100644 (file)
@@ -67,48 +67,47 @@ class tx_rsaauth_sv1 extends tx_sv_auth  {
         */
        public  $scriptRelPath = 'sv1/class.tx_rsaauth_sv1.php';        // Path to this script relative to the extension dir.
 
+
        /**
-        * Authenticates a user. The function decrypts the password, runs evaluations
-        * on it and passes to the parent authentication service.
+        * Process the submitted credentials.
+        * In this case decrypt the password if it is RSA encrypted.
         *
-        * @param       array   $userRecord     User record
-        * @return      int             Code that shows if user is really authenticated.
-        * @see t3lib_userAuth::checkAuthentication()
+        * @param array $loginData Credentials that are submitted and potentially modified by other services
+        * @param string $passwordTransmissionStrategy Keyword of how the password has been hashed or encrypted before submission
+        * @return bool
         */
-       public function authUser(array $userRecord) {
-               $result = 100;
+       public function processLoginData(array &$loginData, $passwordTransmissionStrategy) {
 
-               if ($this->pObj->security_level == 'rsa') {
+               $isProcessed = FALSE;
 
+               if ($passwordTransmissionStrategy === 'rsa') {
                        $storage = tx_rsaauth_storagefactory::getStorage();
                        /* @var $storage tx_rsaauth_abstract_storage */
 
-                       // Set failure status by default
-                       $result = -1;
-
-                       // Preprocess the password
-                       $password = $this->login['uident'];
+                               // Decrypt the password
+                       $password = $loginData['uident'];
                        $key = $storage->get();
-                       if ($key != NULL && substr($password, 0, 4) == 'rsa:') {
-                               // Decode password and pass to parent
+                       if ($key != NULL && substr($password, 0, 4) === 'rsa:') {
+                                       // Decode password and store it in loginData
                                $decryptedPassword = $this->backend->decrypt($key, substr($password, 4));
                                if ($decryptedPassword != NULL) {
-                                       // Run the password through the eval function
-                                       $decryptedPassword = $this->runPasswordEvaluations($decryptedPassword);
-                                       if ($decryptedPassword != NULL) {
-                                               $this->login['uident'] = $decryptedPassword;
-                                               if (parent::authUser($userRecord)) {
-                                                       $result = 200;
-                                               }
+                                       $loginData['uident_text'] = $decryptedPassword;
+                                       $isProcessed = TRUE;
+                               } else {
+                                       if ($this->pObj->writeDevLog) {
+                                               t3lib_div::devLog('Process login data: Failed to RSA decrypt password', 'tx_rsaauth_sv1');
                                        }
                                }
-                               // Reset the password to its original value
-                               $this->login['uident'] = $password;
-                               // Remove the key
+                                       // Remove the key
                                $storage->put(NULL);
+                       } else {
+                               if ($this->pObj->writeDevLog) {
+                                       t3lib_div::devLog('Process login data: passwordTransmissionStrategy has been set to "rsa" but no rsa encrypted password has been found.', 'tx_rsaauth_sv1');
+                               }
                        }
                }
-               return $result;
+
+               return $isProcessed;
        }
 
        /**
@@ -128,69 +127,6 @@ class tx_rsaauth_sv1 extends tx_sv_auth  {
 
                return $available;
        }
-
-       /**
-        * Runs password evaluations. This is necessary because other extensions can
-        * modify the way the password is stored in the database. We check for all
-        * evaluations for the password column and run those.
-        *
-        * Notes:
-        * - we call t3lib_TCEmain::checkValue_input_Eval() but it is risky: if a hook
-        *   relies on BE_USER, it will fail. No hook should do this, so we risk it.
-        * - we cannot use t3lib_TCEmain::checkValue_input_Eval() for running all
-        *   evaluations because it does not create md5 hashes.
-        *
-        * @param       string  $password       Evaluated password
-        * @return      void
-        * @see t3lib_TCEmain::checkValue_input_Eval()
-        */
-       protected function runPasswordEvaluations($password) {
-               $table = $this->pObj->user_table;
-               t3lib_div::loadTCA($table);
-               $conf = &$GLOBALS['TCA'][$table]['columns'][$this->pObj->userident_column]['config'];
-               $evaluations = $conf['eval'];
-               if ($evaluations) {
-                       $tce = NULL;
-                       foreach (t3lib_div::trimExplode(',', $evaluations, TRUE) as $evaluation) {
-                               switch ($evaluation) {
-                                       case 'md5':
-                                               $password = md5($password);
-                                               break;
-                                       case 'upper':
-                                               // We do not pass this to TCEmain because TCEmain will use objects unavailable in FE
-                                               $csConvObj = (TYPO3_MODE == 'BE' ? $GLOBALS['LANG']->csConvObj : $GLOBALS['TSFE']->csConvObj);
-                                               $charset = (TYPO3_MODE == 'BE' ? $GLOBALS['LANG']->charSet : $GLOBALS['TSFE']->metaCharset);
-                                               $password = $csConvObj->conv_case($charset, $password, 'toUpper');
-                                               break;
-                                       case 'lower':
-                                               // We do not pass this to TCEmain because TCEmain will use objects unavailable in FE
-                                               $csConvObj = (TYPO3_MODE == 'BE' ? $GLOBALS['LANG']->csConvObj : $GLOBALS['TSFE']->csConvObj);
-                                               $charset = (TYPO3_MODE == 'BE' ? $GLOBALS['LANG']->charSet : $GLOBALS['TSFE']->metaCharset);
-                                               $password = $csConvObj->conv_case($charset, $password, 'toLower');
-                                               break;
-                                       case 'password':
-                                       case 'required':
-                                               // Do nothing!
-                                               break;
-                                       default:
-                                               // We must run these evaluations through TCEmain to avoid
-                                               // code duplication and ensure that any custom evaluations
-                                               // are called in a proper context
-                                               if ($tce == NULL) {
-                                                       /* @var $tce t3lib_TCEmain */
-                                                       $tce = t3lib_div::makeInstance('t3lib_TCEmain');
-                                               }
-                                               $result = $tce->checkValue_input_Eval($password, array($evaluation), $conf['is_in']);
-                                               if (!isset($result['value'])) {
-                                                       // Failure!!!
-                                                       return NULL;
-                                               }
-                                               $password = $result['value'];
-                               }
-                       }
-               }
-               return $password;
-       }
 }
 
 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/rsaauth/sv1/class.tx_rsaauth_sv1.php'])) {
index 47aab48..bb8d71c 100644 (file)
@@ -225,19 +225,6 @@ class tx_saltedpasswords_sv1 extends tx_sv_authbase {
                $OK = 100;
                $validPasswd = FALSE;
 
-               if ($this->pObj->security_level == 'rsa' && t3lib_extMgm::isLoaded('rsaauth')) {
-                       $backend = tx_rsaauth_backendfactory::getBackend();
-                       $storage = tx_rsaauth_storagefactory::getStorage();
-                               // Preprocess the password
-                       $password = $this->login['uident'];
-                       $key = $storage->get();
-                       if ($key != NULL && substr($password, 0, 4) == 'rsa:') {
-                               // Decode password and pass to parent
-                               $decryptedPassword = $backend->decrypt($key, substr($password, 4));
-                               $this->login['uident_text'] = $decryptedPassword;
-                       }
-               }
-
                if ($this->login['uident'] && $this->login['uname']) {
                        if (!empty($this->login['uident_text'])) {
                                $validPasswd = $this->compareUident(
index 92d4d4d..ab7d506 100644 (file)
  */
 class tx_sv_auth extends tx_sv_authbase        {
 
+       /**
+        * Process the submitted credentials.
+        * In this case hash the clear text password if it has been submitted.
+        *
+        * @param array $loginData Credentials that are submitted and potentially modified by other services
+        * @param string $passwordTransmissionStrategy Keyword of how the password has been hashed or encrypted before submission
+        * @return bool
+        */
+       public function processLoginData(array &$loginData, $passwordTransmissionStrategy) {
+               $isProcessed = TRUE;
+
+                       // Processing data according to the state it was submitted in.
+               switch ($passwordTransmissionStrategy) {
+                       case 'normal':
+                               $loginData['uident_text'] = $loginData['uident'];
+                       break;
+                       case 'challenged':
+                               $loginData['uident_text'] = '';
+                               $loginData['uident_challenged'] = $loginData['uident'];
+                               $loginData['uident_superchallenged'] = '';
+                       break;
+                       case 'superchallenged':
+                               $loginData['uident_text'] = '';
+                               $loginData['uident_challenged'] = '';
+                               $loginData['uident_superchallenged'] = $loginData['uident'];
+                       break;
+                       default:
+                               $isProcessed = FALSE;
+               }
+
+               if (!empty($loginData['uident_text'])) {
+                       $loginData['uident_challenged'] = (string) md5($loginData['uname'] . ':' . $loginData['uident_text'] . ':' . $loginData['chalvalue']);
+                       $loginData['uident_superchallenged'] = (string) md5($loginData['uname'] . ':' . (md5($loginData['uident_text'])) . ':' . $loginData['chalvalue']);
+
+                       $this->processOriginalPasswordValue($loginData);
+
+                       $isProcessed = TRUE;
+               }
+
+               return $isProcessed;
+       }
+
+       /**
+        * This method ensures backwards compatibility of the processed loginData
+        * with older TYPO3 versions.
+        * Starting with TYPO3 4.9 $loginData['uident'] will always contain the raw
+        * value of the submitted password field and will not be processed any further.
+        *
+        * @param array $loginData
+        * @deprecated will be removed with 4.9
+        */
+       protected function processOriginalPasswordValue(&$loginData) {
+               if ($this->authInfo['security_level'] === 'superchallenged') {
+                       $loginData['uident'] = $loginData['uident_superchallenged'];
+               } elseif ($this->authInfo['security_level'] === 'challenged') {
+                       $loginData['uident'] = $loginData['uident_challenged'];
+               }
+       }
 
        /**
         * Find a user (eg. look up the user record in database when a login is sent)
index a3045e6..bd81d54 100644 (file)
@@ -40,9 +40,14 @@ require_once(PATH_t3lib . 'class.t3lib_svbase.php');
  * @package TYPO3
  * @subpackage tx_sv
  */
-class tx_sv_authbase extends t3lib_svbase      {
+class tx_sv_authbase extends t3lib_svbase {
 
-       var $pObj;                      // Parent object
+       /**
+        * User object
+        *
+        * @var t3lib_userAuth
+        */
+       var $pObj;
 
        var $mode;                      // Subtype of the service which is used to call the service.
 
@@ -83,13 +88,24 @@ class tx_sv_authbase extends t3lib_svbase   {
        /**
         * Check the login data with the user record data for builtin login methods
         *
-        * @param       array           user data array
-        * @param       array           login data array
-        * @param       string          security_level
-        * @return      boolean         TRUE if login data matched
+        * @param array $user user data array
+        * @param array $loginData login data array
+        * @param string $passwordCompareStrategy password compare strategy
+        * @return boolean TRUE if login data matched
         */
-       function compareUident(array $user, array $loginData, $security_level = '') {
-               return $this->pObj->compareUident($user, $loginData, $security_level);
+       function compareUident(array $user, array $loginData, $passwordCompareStrategy = '') {
+               if ($this->authInfo['loginType'] === 'BE') {
+                               // Challenge is only stored in session during BE login with the superchallenged login type.
+                               // In the frontend context the challenge is never stored in the session.
+                       if ($passwordCompareStrategy !== 'superchallenged') {
+                               $this->pObj->challengeStoredInCookie = FALSE;
+                       }
+                               // The TYPO3 standard login service relies on $passwordCompareStrategy being set
+                               // to 'superchallenged' because of the password in the database is stored as md5 hash
+                       $passwordCompareStrategy = 'superchallenged';
+               }
+
+               return $this->pObj->compareUident($user, $loginData, $passwordCompareStrategy);
        }
 
        /**
index 7e17e46..271b0b4 100644 (file)
@@ -8,7 +8,7 @@ t3lib_extMgm::addService($_EXTKEY,  'auth' /* sv type */,  'tx_sv_auth' /* sv ke
                        'title' => 'User authentication',
                        'description' => 'Authentication with username/password.',
 
-                       'subtype' => 'getUserBE,authUserBE,getUserFE,authUserFE,getGroupsFE',
+                       'subtype' => 'getUserBE,authUserBE,getUserFE,authUserFE,getGroupsFE,processLoginDataBE,processLoginDataFE',
 
                        'available' => TRUE,
                        'priority' => 50,