AuthenticationSignon.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * SignOn Authentication plugin for phpMyAdmin
  5. *
  6. * @package PhpMyAdmin-Authentication
  7. * @subpackage SignOn
  8. */
  9. namespace PhpMyAdmin\Plugins\Auth;
  10. use PhpMyAdmin\Core;
  11. use PhpMyAdmin\Plugins\AuthenticationPlugin;
  12. use PhpMyAdmin\Response;
  13. use PhpMyAdmin\Util;
  14. /**
  15. * Handles the SignOn authentication method
  16. *
  17. * @package PhpMyAdmin-Authentication
  18. */
  19. class AuthenticationSignon extends AuthenticationPlugin
  20. {
  21. /**
  22. * Displays authentication form
  23. *
  24. * @return boolean always true (no return indeed)
  25. */
  26. public function showLoginForm()
  27. {
  28. Response::getInstance()->disable();
  29. unset($_SESSION['LAST_SIGNON_URL']);
  30. if (empty($GLOBALS['cfg']['Server']['SignonURL'])) {
  31. Core::fatalError('You must set SignonURL!');
  32. } else {
  33. Core::sendHeaderLocation($GLOBALS['cfg']['Server']['SignonURL']);
  34. }
  35. if (!defined('TESTSUITE')) {
  36. exit();
  37. } else {
  38. return false;
  39. }
  40. }
  41. /**
  42. * Set cookie params
  43. *
  44. * @param array $sessionCookieParams The cookie params
  45. * @return void
  46. */
  47. public function setCookieParams(array $sessionCookieParams = null)
  48. {
  49. /* Session cookie params from config */
  50. if ($sessionCookieParams === null) {
  51. $sessionCookieParams = (array) $GLOBALS['cfg']['Server']['SignonCookieParams'];
  52. }
  53. /* Sanitize cookie params */
  54. $defaultCookieParams = function ($key) {
  55. switch ($key) {
  56. case 'lifetime':
  57. return 0;
  58. case 'path':
  59. return '/';
  60. case 'domain':
  61. return '';
  62. case 'secure':
  63. return false;
  64. case 'httponly':
  65. return false;
  66. }
  67. return null;
  68. };
  69. foreach (array('lifetime', 'path', 'domain', 'secure', 'httponly') as $key) {
  70. if (! isset($sessionCookieParams[$key])) {
  71. $sessionCookieParams[$key] = $defaultCookieParams($key);
  72. }
  73. }
  74. if (isset($sessionCookieParams['samesite'])
  75. && ! in_array($sessionCookieParams['samesite'], array('Lax', 'Strict'))) {
  76. // Not a valid value for samesite
  77. unset($sessionCookieParams['samesite']);
  78. }
  79. if (version_compare(phpversion(), '7.3.0', '>=')) {
  80. session_set_cookie_params($sessionCookieParams);
  81. }
  82. session_set_cookie_params(
  83. $sessionCookieParams['lifetime'],
  84. $sessionCookieParams['path'],
  85. $sessionCookieParams['domain'],
  86. $sessionCookieParams['secure'],
  87. $sessionCookieParams['httponly']
  88. );
  89. }
  90. /**
  91. * Gets authentication credentials
  92. *
  93. * @return boolean whether we get authentication settings or not
  94. */
  95. public function readCredentials()
  96. {
  97. /* Check if we're using same signon server */
  98. $signon_url = $GLOBALS['cfg']['Server']['SignonURL'];
  99. if (isset($_SESSION['LAST_SIGNON_URL'])
  100. && $_SESSION['LAST_SIGNON_URL'] != $signon_url
  101. ) {
  102. return false;
  103. }
  104. /* Script name */
  105. $script_name = $GLOBALS['cfg']['Server']['SignonScript'];
  106. /* Session name */
  107. $session_name = $GLOBALS['cfg']['Server']['SignonSession'];
  108. /* Login URL */
  109. $signon_url = $GLOBALS['cfg']['Server']['SignonURL'];
  110. /* Current host */
  111. $single_signon_host = $GLOBALS['cfg']['Server']['host'];
  112. /* Current port */
  113. $single_signon_port = $GLOBALS['cfg']['Server']['port'];
  114. /* No configuration updates */
  115. $single_signon_cfgupdate = array();
  116. /* Handle script based auth */
  117. if (!empty($script_name)) {
  118. if (!@file_exists($script_name)) {
  119. Core::fatalError(
  120. __('Can not find signon authentication script:')
  121. . ' ' . $script_name
  122. );
  123. }
  124. include $script_name;
  125. list ($this->user, $this->password)
  126. = get_login_credentials($GLOBALS['cfg']['Server']['user']);
  127. } elseif (isset($_COOKIE[$session_name])) { /* Does session exist? */
  128. /* End current session */
  129. $old_session = session_name();
  130. $old_id = session_id();
  131. $oldCookieParams = session_get_cookie_params();
  132. if (!defined('TESTSUITE')) {
  133. session_write_close();
  134. }
  135. /* Load single signon session */
  136. if (!defined('TESTSUITE')) {
  137. $this->setCookieParams();
  138. session_name($session_name);
  139. session_id($_COOKIE[$session_name]);
  140. session_start();
  141. }
  142. /* Clear error message */
  143. unset($_SESSION['PMA_single_signon_error_message']);
  144. /* Grab credentials if they exist */
  145. if (isset($_SESSION['PMA_single_signon_user'])) {
  146. $this->user = $_SESSION['PMA_single_signon_user'];
  147. }
  148. if (isset($_SESSION['PMA_single_signon_password'])) {
  149. $this->password = $_SESSION['PMA_single_signon_password'];
  150. }
  151. if (isset($_SESSION['PMA_single_signon_host'])) {
  152. $single_signon_host = $_SESSION['PMA_single_signon_host'];
  153. }
  154. if (isset($_SESSION['PMA_single_signon_port'])) {
  155. $single_signon_port = $_SESSION['PMA_single_signon_port'];
  156. }
  157. if (isset($_SESSION['PMA_single_signon_cfgupdate'])) {
  158. $single_signon_cfgupdate = $_SESSION['PMA_single_signon_cfgupdate'];
  159. }
  160. /* Also get token as it is needed to access subpages */
  161. if (isset($_SESSION['PMA_single_signon_token'])) {
  162. /* No need to care about token on logout */
  163. $pma_token = $_SESSION['PMA_single_signon_token'];
  164. }
  165. /* End single signon session */
  166. if (!defined('TESTSUITE')) {
  167. session_write_close();
  168. }
  169. /* Restart phpMyAdmin session */
  170. if (!defined('TESTSUITE')) {
  171. $this->setCookieParams($oldCookieParams);
  172. session_name($old_session);
  173. if (!empty($old_id)) {
  174. session_id($old_id);
  175. }
  176. session_start();
  177. }
  178. /* Set the single signon host */
  179. $GLOBALS['cfg']['Server']['host'] = $single_signon_host;
  180. /* Set the single signon port */
  181. $GLOBALS['cfg']['Server']['port'] = $single_signon_port;
  182. /* Configuration update */
  183. $GLOBALS['cfg']['Server'] = array_merge(
  184. $GLOBALS['cfg']['Server'],
  185. $single_signon_cfgupdate
  186. );
  187. /* Restore our token */
  188. if (!empty($pma_token)) {
  189. $_SESSION[' PMA_token '] = $pma_token;
  190. $_SESSION[' HMAC_secret '] = Util::generateRandom(16);
  191. }
  192. /**
  193. * Clear user cache.
  194. */
  195. Util::clearUserCache();
  196. }
  197. // Returns whether we get authentication settings or not
  198. if (empty($this->user)) {
  199. unset($_SESSION['LAST_SIGNON_URL']);
  200. return false;
  201. }
  202. $_SESSION['LAST_SIGNON_URL'] = $GLOBALS['cfg']['Server']['SignonURL'];
  203. return true;
  204. }
  205. /**
  206. * User is not allowed to login to MySQL -> authentication failed
  207. *
  208. * @param string $failure String describing why authentication has failed
  209. *
  210. * @return void
  211. */
  212. public function showFailure($failure)
  213. {
  214. parent::showFailure($failure);
  215. /* Session name */
  216. $session_name = $GLOBALS['cfg']['Server']['SignonSession'];
  217. /* Does session exist? */
  218. if (isset($_COOKIE[$session_name])) {
  219. if (!defined('TESTSUITE')) {
  220. /* End current session */
  221. session_write_close();
  222. /* Load single signon session */
  223. $this->setCookieParams();
  224. session_name($session_name);
  225. session_id($_COOKIE[$session_name]);
  226. session_start();
  227. }
  228. /* Set error message */
  229. $_SESSION['PMA_single_signon_error_message'] = $this->getErrorMessage($failure);
  230. }
  231. $this->showLoginForm();
  232. }
  233. /**
  234. * Returns URL for login form.
  235. *
  236. * @return string
  237. */
  238. public function getLoginFormURL()
  239. {
  240. return $GLOBALS['cfg']['Server']['SignonURL'];
  241. }
  242. }