TYPO3 API  SVNRelease
tx_saltedpasswords_salts_md5Test.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 2009-2011 Marcus Krause <marcus#exp2009@t3sec.info>
00006 *  All rights reserved
00007 *
00008 *  This script is part of the TYPO3 project. The TYPO3 project is
00009 *  free software; you can redistribute it and/or modify
00010 *  it under the terms of the GNU General Public License as published by
00011 *  the Free Software Foundation; either version 2 of the License, or
00012 *  (at your option) any later version.
00013 *
00014 *  The GNU General Public License can be found at
00015 *  http://www.gnu.org/copyleft/gpl.html.
00016 *  A copy is found in the textfile GPL.txt and important notices to the license
00017 *  from the author is found in LICENSE.txt distributed with these scripts.
00018 *
00019 *
00020 *  This script is distributed in the hope that it will be useful,
00021 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 *  GNU General Public License for more details.
00024 *
00025 *  This copyright notice MUST APPEAR in all copies of the script!
00026 ***************************************************************/
00027 /**
00028  * Contains testcases for "tx_saltedpasswords_salts_md5"
00029  * that provides MD5 salted hashing.
00030  *
00031  * $Id: tx_saltedpasswords_salts_md5Test.php 10120 2011-01-18 20:03:36Z ohader $
00032  */
00033 
00034 /**
00035  * Testcases for class tx_saltedpasswords_salts_md5.
00036  *
00037  * @author  Marcus Krause <marcus#exp2009@t3sec.info>
00038  * @package  TYPO3
00039  * @subpackage  tx_saltedpasswords
00040  */
00041 class tx_saltedpasswords_salts_md5Test extends tx_phpunit_testcase {
00042 
00043 
00044     /**
00045      * Keeps instance of object to test.
00046      *
00047      * @var tx_saltedpasswords_salts_md5
00048      */
00049     protected $objectInstance = NULL;
00050 
00051 
00052     /**
00053      * Sets up the fixtures for this testcase.
00054      *
00055      * @return  void
00056      */
00057     public function setUp() {
00058         $this->objectInstance = t3lib_div::makeInstance('tx_saltedpasswords_salts_md5');
00059     }
00060 
00061     /**
00062      * Tears down objects and settings created in this testcase.
00063      *
00064      * @return  void
00065      */
00066     public function tearDown() {
00067         unset($this->objectInstance);
00068     }
00069 
00070     /**
00071      * Prepares a message to be shown when a salted hashing is not supported.
00072      *
00073      * @return  string     empty string if salted hashing method is available, otherwise an according warning
00074      */
00075     protected function getWarningWhenMethodUnavailable() {
00076         $warningMsg = '';
00077         if (!CRYPT_MD5) {
00078             $warningMsg .= 'MD5 is not supported on your platform. '
00079                         .  'Then, some of the md5 tests will fail.';
00080         }
00081     }
00082 
00083     /**
00084      * @test
00085      */
00086     public function hasCorrectBaseClass() {
00087 
00088         $hasCorrectBaseClass = (0 === strcmp('tx_saltedpasswords_salts_md5', get_class($this->objectInstance))) ? TRUE : FALSE;
00089 
00090             // XCLASS ?
00091         if (!$hasCorrectBaseClass && FALSE != get_parent_class($this->objectInstance)) {
00092             $hasCorrectBaseClass = is_subclass_of($this->objectInstance, 'tx_saltedpasswords_salts_md5');
00093         }
00094 
00095         $this->assertTrue($hasCorrectBaseClass);
00096     }
00097 
00098     /**
00099      * @test
00100      */
00101     public function nonZeroSaltLength() {
00102         $this->assertTrue($this->objectInstance->getSaltLength() > 0);
00103     }
00104 
00105     /**
00106      * @test
00107      */
00108     public function emptyPasswordResultsInNullSaltedPassword() {
00109         $password = '';
00110         $this->assertNull($this->objectInstance->getHashedPassword($password));
00111     }
00112 
00113     /**
00114      * @test
00115      */
00116     public function nonEmptyPasswordResultsInNonNullSaltedPassword() {
00117         $password = 'a';
00118         $this->assertNotNull($this->objectInstance->getHashedPassword($password), $this->getWarningWhenMethodUnavailable());
00119     }
00120 
00121     /**
00122      * @test
00123      */
00124     public function createdSaltedHashOfProperStructure() {
00125         $password = 'password';
00126         $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
00127         $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword), $this->getWarningWhenMethodUnavailable());
00128     }
00129 
00130     /**
00131      * @test
00132      */
00133     public function createdSaltedHashOfProperStructureForCustomSaltWithoutSetting() {
00134         $password = 'password';
00135 
00136             // custom salt without setting
00137         $randomBytes = t3lib_div::generateRandomBytes($this->objectInstance->getSaltLength());
00138         $salt = $this->objectInstance->base64Encode($randomBytes, $this->objectInstance->getSaltLength());
00139         $this->assertTrue($this->objectInstance->isValidSalt($salt), $this->getWarningWhenMethodUnavailable());
00140 
00141         $saltedHashPassword = $this->objectInstance->getHashedPassword($password, $salt);
00142         $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword), $this->getWarningWhenMethodUnavailable());
00143     }
00144 
00145     /**
00146      * Tests authentication procedure with alphabet characters.
00147      *
00148      * Checks if a "plain-text password" is everytime mapped to the
00149      * same "salted password hash" when using the same salt.
00150      *
00151      * @test
00152      */
00153     public function authenticationWithValidAlphaCharClassPassword() {
00154         $password = 'aEjOtY';
00155 
00156         $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
00157         $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
00158     }
00159 
00160     /**
00161      * Tests authentication procedure with numeric characters.
00162      *
00163      * Checks if a "plain-text password" is everytime mapped to the
00164      * same "salted password hash" when using the same salt.
00165      *
00166      * @test
00167      */
00168     public function authenticationWithValidNumericCharClassPassword() {
00169         $password = '01369';
00170 
00171         $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
00172         $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
00173     }
00174 
00175     /**
00176      * Tests authentication procedure with US-ASCII special characters.
00177      *
00178      * Checks if a "plain-text password" is everytime mapped to the
00179      * same "salted password hash" when using the same salt.
00180      *
00181      * @test
00182      */
00183     public function authenticationWithValidAsciiSpecialCharClassPassword() {
00184         $password = ' !"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~';
00185 
00186         $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
00187         $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
00188     }
00189 
00190     /**
00191      * Tests authentication procedure with latin1 special characters.
00192      *
00193      * Checks if a "plain-text password" is everytime mapped to the
00194      * same "salted password hash" when using the same salt.
00195      *
00196      * @test
00197      */
00198     public function authenticationWithValidLatin1SpecialCharClassPassword() {
00199         $password = '';
00200         for ($i = 160; $i <= 191; $i++) {
00201             $password .= chr($i);
00202         }
00203         $password .= chr(215) . chr(247);
00204 
00205         $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
00206         $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
00207     }
00208 
00209     /**
00210      * Tests authentication procedure with latin1 umlauts.
00211      *
00212      * Checks if a "plain-text password" is everytime mapped to the
00213      * same "salted password hash" when using the same salt.
00214      *
00215      * @test
00216      */
00217     public function authenticationWithValidLatin1UmlautCharClassPassword() {
00218         $password = '';
00219         for ($i = 192; $i <= 214; $i++) {
00220             $password .= chr($i);
00221         }
00222         for ($i = 216; $i <= 246; $i++) {
00223             $password .= chr($i);
00224         }
00225         for ($i = 248; $i <= 255; $i++) {
00226             $password .= chr($i);
00227         }
00228 
00229         $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
00230         $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
00231     }
00232 
00233     /**
00234      * @test
00235      */
00236     public function authenticationWithNonValidPassword() {
00237         $password = 'password';
00238         $password1 = $password . 'INVALID';
00239         $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
00240         $this->assertFalse($this->objectInstance->checkPassword($password1, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
00241     }
00242 
00243     /**
00244      * @test
00245      */
00246     public function passwordVariationsResultInDifferentHashes() {
00247         $pad = 'a';
00248         $password = '';
00249         $criticalPwLength = 0;
00250             // We're using a constant salt.
00251         $saltedHashPasswordPrevious = $saltedHashPasswordCurrent = $salt = $this->objectInstance->getHashedPassword($pad);
00252         for ($i = 0; $i <= 128; $i += 8) {
00253             $password = str_repeat($pad, max($i, 1));
00254             $saltedHashPasswordPrevious = $saltedHashPasswordCurrent;
00255             $saltedHashPasswordCurrent = $this->objectInstance->getHashedPassword($password, $salt);
00256             if ($i > 0 && 0 == strcmp($saltedHashPasswordPrevious, $saltedHashPasswordCurrent)) {
00257                 $criticalPwLength = $i;
00258                 break;
00259             }
00260         }
00261         $this->assertTrue(($criticalPwLength == 0) || ($criticalPwLength > 32), $this->getWarningWhenMethodUnavailable() . 'Duplicates of hashed passwords with plaintext password of length ' . $criticalPwLength . '+.');
00262     }
00263 
00264     /**
00265      * @test
00266      */
00267     public function noUpdateNecessityForMd5() {
00268         $password = 'password';
00269         $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
00270         $this->assertFalse($this->objectInstance->isHashUpdateNeeded($saltedHashPassword));
00271     }
00272 }
00273 ?>