AuthenticationHttp.class.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * HTTP Authentication plugin for phpMyAdmin.
  5. * NOTE: Requires PHP loaded as a Apache module.
  6. *
  7. * @package PhpMyAdmin-Authentication
  8. * @subpackage HTTP
  9. */
  10. if (! defined('PHPMYADMIN')) {
  11. exit;
  12. }
  13. /* Get the authentication interface */
  14. require_once 'libraries/plugins/AuthenticationPlugin.class.php';
  15. /**
  16. * Handles the HTTP authentication methods
  17. *
  18. * @package PhpMyAdmin-Authentication
  19. */
  20. class AuthenticationHttp extends AuthenticationPlugin
  21. {
  22. /**
  23. * Displays authentication form
  24. *
  25. * @global string the font face to use in case of failure
  26. * @global string the default font size to use in case of failure
  27. * @global string the big font size to use in case of failure
  28. *
  29. * @return boolean always true (no return indeed)
  30. */
  31. public function auth()
  32. {
  33. /* Perform logout to custom URL */
  34. if (! empty($_REQUEST['old_usr'])
  35. && ! empty($GLOBALS['cfg']['Server']['LogoutURL'])
  36. ) {
  37. PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['LogoutURL']);
  38. if (! defined('TESTSUITE')) {
  39. exit;
  40. } else {
  41. return false;
  42. }
  43. }
  44. if (empty($GLOBALS['cfg']['Server']['auth_http_realm'])) {
  45. if (empty($GLOBALS['cfg']['Server']['verbose'])) {
  46. $server_message = $GLOBALS['cfg']['Server']['host'];
  47. } else {
  48. $server_message = $GLOBALS['cfg']['Server']['verbose'];
  49. }
  50. $realm_message = 'phpMyAdmin ' . $server_message;
  51. } else {
  52. $realm_message = $GLOBALS['cfg']['Server']['auth_http_realm'];
  53. }
  54. // remove non US-ASCII to respect RFC2616
  55. $realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message);
  56. header('WWW-Authenticate: Basic realm="' . $realm_message . '"');
  57. header('HTTP/1.0 401 Unauthorized');
  58. if (php_sapi_name() !== 'cgi-fcgi') {
  59. header('status: 401 Unauthorized');
  60. }
  61. /* HTML header */
  62. $response = PMA_Response::getInstance();
  63. $response->getFooter()->setMinimal();
  64. $header = $response->getHeader();
  65. $header->setTitle(__('Access denied!'));
  66. $header->disableMenu();
  67. $header->setBodyId('loginform');
  68. $response->addHTML('<h1>');
  69. $response->addHTML(sprintf(__('Welcome to %s'), ' phpMyAdmin'));
  70. $response->addHTML('</h1>');
  71. $response->addHTML('<h3>');
  72. $response->addHTML(
  73. PMA_Message::error(
  74. __('Wrong username/password. Access denied.')
  75. )
  76. );
  77. $response->addHTML('</h3>');
  78. if (file_exists(CUSTOM_FOOTER_FILE)) {
  79. include CUSTOM_FOOTER_FILE;
  80. }
  81. if (! defined('TESTSUITE')) {
  82. exit;
  83. } else {
  84. return false;
  85. }
  86. }
  87. /**
  88. * Gets advanced authentication settings
  89. *
  90. * @global string $PHP_AUTH_USER the username if register_globals is on
  91. * @global string $PHP_AUTH_PW the password if register_globals is on
  92. * @global array the array of server variables if
  93. * register_globals is off
  94. * @global array the array of environment variables if
  95. * register_globals is off
  96. * @global string the username for the ? server
  97. * @global string the password for the ? server
  98. * @global string the username for the WebSite Professional
  99. * server
  100. * @global string the password for the WebSite Professional
  101. * server
  102. * @global string the username of the user who logs out
  103. *
  104. * @return boolean whether we get authentication settings or not
  105. */
  106. public function authCheck()
  107. {
  108. global $PHP_AUTH_USER, $PHP_AUTH_PW;
  109. // Grabs the $PHP_AUTH_USER variable whatever are the values of the
  110. // 'register_globals' and the 'variables_order' directives
  111. if (empty($PHP_AUTH_USER)) {
  112. if (PMA_getenv('PHP_AUTH_USER')) {
  113. $PHP_AUTH_USER = PMA_getenv('PHP_AUTH_USER');
  114. } elseif (PMA_getenv('REMOTE_USER')) {
  115. // CGI, might be encoded, see below
  116. $PHP_AUTH_USER = PMA_getenv('REMOTE_USER');
  117. } elseif (PMA_getenv('REDIRECT_REMOTE_USER')) {
  118. // CGI, might be encoded, see below
  119. $PHP_AUTH_USER = PMA_getenv('REDIRECT_REMOTE_USER');
  120. } elseif (PMA_getenv('AUTH_USER')) {
  121. // WebSite Professional
  122. $PHP_AUTH_USER = PMA_getenv('AUTH_USER');
  123. } elseif (PMA_getenv('HTTP_AUTHORIZATION')
  124. && false === strpos(PMA_getenv('HTTP_AUTHORIZATION'), '<')
  125. ) {
  126. // IIS, might be encoded, see below; also prevent XSS
  127. $PHP_AUTH_USER = PMA_getenv('HTTP_AUTHORIZATION');
  128. } elseif (PMA_getenv('Authorization')) {
  129. // FastCGI, might be encoded, see below
  130. $PHP_AUTH_USER = PMA_getenv('Authorization');
  131. }
  132. }
  133. // Grabs the $PHP_AUTH_PW variable whatever are the values of the
  134. // 'register_globals' and the 'variables_order' directives
  135. if (empty($PHP_AUTH_PW)) {
  136. if (PMA_getenv('PHP_AUTH_PW')) {
  137. $PHP_AUTH_PW = PMA_getenv('PHP_AUTH_PW');
  138. } elseif (PMA_getenv('REMOTE_PASSWORD')) {
  139. // Apache/CGI
  140. $PHP_AUTH_PW = PMA_getenv('REMOTE_PASSWORD');
  141. } elseif (PMA_getenv('AUTH_PASSWORD')) {
  142. // WebSite Professional
  143. $PHP_AUTH_PW = PMA_getenv('AUTH_PASSWORD');
  144. }
  145. }
  146. // Decode possibly encoded information (used by IIS/CGI/FastCGI)
  147. // (do not use explode() because a user might have a colon in his password
  148. if (strcmp(substr($PHP_AUTH_USER, 0, 6), 'Basic ') == 0) {
  149. $usr_pass = base64_decode(substr($PHP_AUTH_USER, 6));
  150. if (! empty($usr_pass)) {
  151. $colon = strpos($usr_pass, ':');
  152. if ($colon) {
  153. $PHP_AUTH_USER = substr($usr_pass, 0, $colon);
  154. $PHP_AUTH_PW = substr($usr_pass, $colon + 1);
  155. }
  156. unset($colon);
  157. }
  158. unset($usr_pass);
  159. }
  160. // User logged out -> ensure the new username is not the same
  161. $old_usr = isset($_REQUEST['old_usr']) ? $_REQUEST['old_usr'] : '';
  162. if (! empty($old_usr)
  163. && (isset($PHP_AUTH_USER) && $old_usr == $PHP_AUTH_USER)
  164. ) {
  165. $PHP_AUTH_USER = '';
  166. // -> delete user's choices that were stored in session
  167. if (! defined('TESTSUITE')) {
  168. session_destroy();
  169. }
  170. }
  171. // Returns whether we get authentication settings or not
  172. if (empty($PHP_AUTH_USER)) {
  173. return false;
  174. } else {
  175. return true;
  176. }
  177. }
  178. /**
  179. * Set the user and password after last checkings if required
  180. *
  181. * @global array $cfg the valid servers settings
  182. * @global integer $server the id of the current server
  183. * @global array the current server settings
  184. * @global string $PHP_AUTH_USER the current username
  185. * @global string $PHP_AUTH_PW the current password
  186. *
  187. * @return boolean always true
  188. */
  189. public function authSetUser()
  190. {
  191. global $cfg, $server;
  192. global $PHP_AUTH_USER, $PHP_AUTH_PW;
  193. // Ensures valid authentication mode, 'only_db', bookmark database and
  194. // table names and relation table name are used
  195. if ($cfg['Server']['user'] != $PHP_AUTH_USER) {
  196. $servers_cnt = count($cfg['Servers']);
  197. for ($i = 1; $i <= $servers_cnt; $i++) {
  198. if (isset($cfg['Servers'][$i])
  199. && ($cfg['Servers'][$i]['host'] == $cfg['Server']['host']
  200. && $cfg['Servers'][$i]['user'] == $PHP_AUTH_USER)
  201. ) {
  202. $server = $i;
  203. $cfg['Server'] = $cfg['Servers'][$i];
  204. break;
  205. }
  206. } // end for
  207. } // end if
  208. $cfg['Server']['user'] = $PHP_AUTH_USER;
  209. $cfg['Server']['password'] = $PHP_AUTH_PW;
  210. // Avoid showing the password in phpinfo()'s output
  211. unset($GLOBALS['PHP_AUTH_PW']);
  212. unset($_SERVER['PHP_AUTH_PW']);
  213. // try to workaround PHP 5 session garbage collection which
  214. // looks at the session file's last modified time
  215. $_SESSION['last_access_time'] = time();
  216. return true;
  217. }
  218. /**
  219. * User is not allowed to login to MySQL -> authentication failed
  220. *
  221. * @return boolean always true (no return indeed)
  222. */
  223. public function authFails()
  224. {
  225. $error = $GLOBALS['dbi']->getError();
  226. if ($error && $GLOBALS['errno'] != 1045) {
  227. PMA_fatalError($error);
  228. } else {
  229. $this->auth();
  230. return true;
  231. }
  232. }
  233. /**
  234. * This method is called when any PluginManager to which the observer
  235. * is attached calls PluginManager::notify()
  236. *
  237. * @param SplSubject $subject The PluginManager notifying the observer
  238. * of an update.
  239. *
  240. * @return void
  241. */
  242. public function update (SplSubject $subject)
  243. {
  244. }
  245. }