SproutCMS

This is the code documentation for the SproutCMS project

source of /sprout/Helpers/Auth.php

  1. <?php
  2. /*
  3.  * Copyright (C) 2017 Karmabunny Pty Ltd.
  4.  *
  5.  * This file is a part of SproutCMS.
  6.  *
  7.  * SproutCMS is free software: you can redistribute it and/or modify it under the terms
  8.  * of the GNU General Public License as published by the Free Software Foundation, either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * For more information, visit <http://getsproutcms.com>.
  12.  */
  13.  
  14. namespace Sprout\Helpers;
  15.  
  16. use Exception;
  17. use InvalidArgumentException;
  18.  
  19.  
  20. /**
  21. * Provides user authentication functions for the admin
  22. **/
  23. class Auth
  24. {
  25.  
  26. /**
  27.   * Check a password hash against an entered password
  28.   *
  29.   * @param string $known_hash The known hash to check against, typically from the database
  30.   * @param int $algorithm Password algorithm, {@see Constants}
  31.   * @param string $salt
  32.   * @param string $user_string Password which was entered by the user, to check against the stored hash
  33.   * @return bool True if the password matches, false if it doesn't
  34.   */
  35. public static function doPasswordCheck($known_hash, $algorithm, $salt, $user_string)
  36. {
  37. switch ($algorithm) {
  38. case Constants::PASSWORD_SHA:
  39. $expected = sha1($user_string);
  40. return Security::compareStrings($known_hash, $expected);
  41.  
  42. case Constants::PASSWORD_SHA_SALT:
  43. $expected = sha1(sha1($salt . $user_string . $salt));
  44. return Security::compareStrings($known_hash, $expected);
  45.  
  46. case Constants::PASSWORD_SHA_SALT_5000:
  47. $expected = $salt . $user_string . $salt;
  48. for ($i = 1; $i <= 5000; $i++) {
  49. $expected = sha1($expected);
  50. }
  51. return Security::compareStrings($known_hash, $expected);
  52.  
  53. case Constants::PASSWORD_BCRYPT12:
  54. // The entire known password is used as a salt when generating the expected hash
  55. $expected = crypt($user_string, $known_hash);
  56. return Security::compareStrings($known_hash, $expected);
  57. }
  58.  
  59. return false;
  60. }
  61.  
  62.  
  63. /**
  64.   * Return a hashed password, password algorithm, and salt, for inserting into the database
  65.   *
  66.   * @param string $password Plaintext password
  67.   * @param int $algorithmPassword algorithm, {@see Constants}. If not specified, the default is used.
  68.   * @return array 0 => hash, 1 => algorithm, 2 => salt
  69.   */
  70. public static function hashPassword($password, $algorithm = null)
  71. {
  72. if ($algorithm == null) {
  73. $algorithm = self::defaultAlgorithm();
  74. }
  75.  
  76. switch ($algorithm) {
  77. case Constants::PASSWORD_PLAIN:
  78. case Constants::PASSWORD_SHA:
  79. throw new InvalidArgumentException('Read-only password algorithm specified');
  80. break;
  81.  
  82. case Constants::PASSWORD_SHA_SALT:
  83. $salt = Security::randStr(10);
  84. $hash = sha1(sha1($salt . $password . $salt));
  85. break;
  86.  
  87. case Constants::PASSWORD_SHA_SALT_5000:
  88. $salt = Security::randStr(10);
  89. $hash = $salt . $password . $salt;
  90. for ($i = 1; $i <= 5000; $i++) {
  91. $hash = sha1($hash);
  92. }
  93. break;
  94.  
  95. case Constants::PASSWORD_BCRYPT12:
  96. $salt = '$2y$12$';
  97. $salt .= Security::randStr(22, './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789');
  98.  
  99. $hash = crypt($password, $salt);
  100. if (strlen($hash) <= 12) {
  101. throw new Exception('Bcrypt hashing failed');
  102. }
  103.  
  104. // Unit tests check whether this field is set, but it's not used
  105. // so it's just set to a dummy value
  106. $salt = Sprout::randStr(4);
  107. break;
  108.  
  109. default:
  110. return null;
  111. }
  112.  
  113. return array($hash, $algorithm, $salt);
  114. }
  115.  
  116.  
  117. /**
  118.   * Checks if a given password algorithm is available
  119.   *
  120.   * @param int $algorithm Password algorithm, {@see Constants}
  121.   * @return bool True if the specified algorithm is available, False otherwise
  122.   */
  123. public static function checkAlgorithm($algorithm)
  124. {
  125. switch ($algorithm) {
  126. case Constants::PASSWORD_SHA:
  127. case Constants::PASSWORD_SHA_SALT:
  128. case Constants::PASSWORD_PLAIN:
  129. case Constants::PASSWORD_SHA_SALT_5000:
  130. return true;
  131.  
  132. case Constants::PASSWORD_BCRYPT12:
  133. return (CRYPT_BLOWFISH == 1);
  134. }
  135.  
  136. return false;
  137. }
  138.  
  139.  
  140. /**
  141.   * Return the algorithm for new accounts.
  142.   * Existing accounts will be re-crypted into this algorithm upon next login.
  143.   *
  144.   * @return int Password algorithm, {@see Constants}
  145.   **/
  146. public static function defaultAlgorithm()
  147. {
  148. if (self::checkAlgorithm(Constants::PASSWORD_BCRYPT12)) {
  149. return Constants::PASSWORD_BCRYPT12;
  150. } else {
  151. return Constants::PASSWORD_SHA_SALT_5000;
  152. }
  153. }
  154.  
  155. }
  156.