913663b29b4b1f824c79d1504c5d7c120f2f7afe
[Packages/TYPO3.CMS.git] / typo3 / sysext / saltedpasswords / Classes / Salt / SaltFactory.php
1 <?php
2 namespace TYPO3\CMS\Saltedpasswords\Salt;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * Class that implements Blowfish salted hashing based on PHP's
19 * crypt() function.
20 */
21 class SaltFactory
22 {
23 /**
24 * An instance of the salted hashing method.
25 * This member is set in the getSaltingInstance() function.
26 *
27 * @var \TYPO3\CMS\Saltedpasswords\Salt\AbstractSalt
28 */
29 protected static $instance = null;
30
31 /**
32 * Returns list of all registered hashing methods. Used eg. in
33 * extension configuration to select the default hashing method.
34 *
35 * @return array
36 */
37 public static function getRegisteredSaltedHashingMethods()
38 {
39 $saltMethods = static::getDefaultSaltMethods();
40 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/saltedpasswords']['saltMethods'])) {
41 $configuredMethods = (array)$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/saltedpasswords']['saltMethods'];
42 if (!empty($configuredMethods)) {
43 if (isset($configuredMethods[0])) {
44 // ensure the key of the array is not numeric, but a class name
45 foreach ($configuredMethods as $method) {
46 $saltMethods[$method] = $method;
47 }
48 } else {
49 $saltMethods = array_merge($saltMethods, $configuredMethods);
50 }
51 }
52 }
53 return $saltMethods;
54 }
55
56 /**
57 * Returns an array with default salt method class names.
58 *
59 * @return array
60 */
61 protected static function getDefaultSaltMethods()
62 {
63 return [
64 \TYPO3\CMS\Saltedpasswords\Salt\Md5Salt::class => \TYPO3\CMS\Saltedpasswords\Salt\Md5Salt::class,
65 \TYPO3\CMS\Saltedpasswords\Salt\BlowfishSalt::class => \TYPO3\CMS\Saltedpasswords\Salt\BlowfishSalt::class,
66 \TYPO3\CMS\Saltedpasswords\Salt\PhpassSalt::class => \TYPO3\CMS\Saltedpasswords\Salt\PhpassSalt::class,
67 \TYPO3\CMS\Saltedpasswords\Salt\Pbkdf2Salt::class => \TYPO3\CMS\Saltedpasswords\Salt\Pbkdf2Salt::class
68 ];
69 }
70
71 /**
72 * Obtains a salting hashing method instance.
73 *
74 * This function will return an instance of a class that implements
75 * \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface
76 *
77 * Use parameter NULL to reset the factory!
78 *
79 * @param string|NULL $saltedHash Salted hashed password to determine the type of used method from or NULL to reset to the default type
80 * @param string $mode The TYPO3 mode (FE or BE) saltedpasswords shall be used for
81 * @return SaltInterface An instance of salting hash method class
82 */
83 public static function getSaltingInstance($saltedHash = '', $mode = TYPO3_MODE)
84 {
85 // Creating new instance when
86 // * no instance existing
87 // * a salted hash given to determine salted hashing method from
88 // * a NULL parameter given to reset instance back to default method
89 if (!is_object(self::$instance) || !empty($saltedHash) || $saltedHash === null) {
90 // Determine method by checking the given hash
91 if (!empty($saltedHash)) {
92 $result = self::determineSaltingHashingMethod($saltedHash, $mode);
93 if (!$result) {
94 self::$instance = null;
95 }
96 } else {
97 $classNameToUse = \TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::getDefaultSaltingHashingMethod($mode);
98 $availableClasses = static::getRegisteredSaltedHashingMethods();
99 self::$instance = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($availableClasses[$classNameToUse]);
100 }
101 }
102 return self::$instance;
103 }
104
105 /**
106 * Method tries to determine the salting hashing method used for given salt.
107 *
108 * Method implicitly sets the instance of the found method object in the class property when found.
109 *
110 * @param string $saltedHash
111 * @param string $mode (optional) The TYPO3 mode (FE or BE) saltedpasswords shall be used for
112 * @return bool TRUE, if salting hashing method has been found, otherwise FALSE
113 */
114 public static function determineSaltingHashingMethod($saltedHash, $mode = TYPO3_MODE)
115 {
116 $registeredMethods = static::getRegisteredSaltedHashingMethods();
117 $defaultClassName = \TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::getDefaultSaltingHashingMethod($mode);
118 $defaultReference = $registeredMethods[$defaultClassName];
119 unset($registeredMethods[$defaultClassName]);
120 // place the default method first in the order
121 $registeredMethods = [$defaultClassName => $defaultReference] + $registeredMethods;
122 $methodFound = false;
123 foreach ($registeredMethods as $method) {
124 $objectInstance = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($method);
125 if ($objectInstance instanceof SaltInterface) {
126 $methodFound = $objectInstance->isValidSaltedPW($saltedHash);
127 if ($methodFound) {
128 self::$instance = $objectInstance;
129 break;
130 }
131 }
132 }
133 return $methodFound;
134 }
135
136 /**
137 * Method sets a custom salting hashing method class.
138 *
139 * @param string $resource Object resource to use (e.g. \TYPO3\CMS\Saltedpasswords\Salt\BlowfishSalt::class)
140 * @return \TYPO3\CMS\Saltedpasswords\Salt\AbstractSalt An instance of salting hashing method object
141 */
142 public static function setPreferredHashingMethod($resource)
143 {
144 self::$instance = null;
145 $objectInstance = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($resource);
146 if (is_object($objectInstance) && is_subclass_of($objectInstance, \TYPO3\CMS\Saltedpasswords\Salt\AbstractSalt::class)) {
147 self::$instance = $objectInstance;
148 }
149 return self::$instance;
150 }
151 }