AuthenticationHttp.class.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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. exit;
  39. }
  40. if (empty($GLOBALS['cfg']['Server']['auth_http_realm'])) {
  41. if (empty($GLOBALS['cfg']['Server']['verbose'])) {
  42. $server_message = $GLOBALS['cfg']['Server']['host'];
  43. } else {
  44. $server_message = $GLOBALS['cfg']['Server']['verbose'];
  45. }
  46. $realm_message = 'phpMyAdmin ' . $server_message;
  47. } else {
  48. $realm_message = $GLOBALS['cfg']['Server']['auth_http_realm'];
  49. }
  50. // remove non US-ASCII to respect RFC2616
  51. $realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message);
  52. header('WWW-Authenticate: Basic realm="' . $realm_message . '"');
  53. header('HTTP/1.0 401 Unauthorized');
  54. if (php_sapi_name() !== 'cgi-fcgi') {
  55. header('status: 401 Unauthorized');
  56. }
  57. /* HTML header */
  58. $response = PMA_Response::getInstance();
  59. $response->getFooter()->setMinimal();
  60. $header = $response->getHeader();
  61. $header->setTitle(__('Access denied'));
  62. $header->disableMenu();
  63. $header->setBodyId('loginform');
  64. $response->addHTML('<h1>');
  65. $response->addHTML(sprintf(__('Welcome to %s'), ' phpMyAdmin'));
  66. $response->addHTML('</h1>');
  67. $response->addHTML('<h3>');
  68. $response->addHTML(
  69. PMA_Message::error(
  70. __('Wrong username/password. Access denied.')
  71. )
  72. );
  73. $response->addHTML('</h3>');
  74. if (file_exists(CUSTOM_FOOTER_FILE)) {
  75. include CUSTOM_FOOTER_FILE;
  76. }
  77. exit;
  78. }
  79. /**
  80. * Gets advanced authentication settings
  81. *
  82. * @global string the username if register_globals is on
  83. * @global string the password if register_globals is on
  84. * @global array the array of server variables if register_globals is
  85. * off
  86. * @global array the array of environment variables if register_globals
  87. * is off
  88. * @global string the username for the ? server
  89. * @global string the password for the ? server
  90. * @global string the username for the WebSite Professional server
  91. * @global string the password for the WebSite Professional server
  92. * @global string the username of the user who logs out
  93. *
  94. * @return boolean whether we get authentication settings or not
  95. */
  96. public function authCheck()
  97. {
  98. global $PHP_AUTH_USER, $PHP_AUTH_PW;
  99. // Grabs the $PHP_AUTH_USER variable whatever are the values of the
  100. // 'register_globals' and the 'variables_order' directives
  101. if (empty($PHP_AUTH_USER)) {
  102. if (PMA_getenv('PHP_AUTH_USER')) {
  103. $PHP_AUTH_USER = PMA_getenv('PHP_AUTH_USER');
  104. } elseif (PMA_getenv('REMOTE_USER')) {
  105. // CGI, might be encoded, see below
  106. $PHP_AUTH_USER = PMA_getenv('REMOTE_USER');
  107. } elseif (PMA_getenv('REDIRECT_REMOTE_USER')) {
  108. // CGI, might be encoded, see below
  109. $PHP_AUTH_USER = PMA_getenv('REDIRECT_REMOTE_USER');
  110. } elseif (PMA_getenv('AUTH_USER')) {
  111. // WebSite Professional
  112. $PHP_AUTH_USER = PMA_getenv('AUTH_USER');
  113. } elseif (PMA_getenv('HTTP_AUTHORIZATION')
  114. && false === strpos(PMA_getenv('HTTP_AUTHORIZATION'), '<')
  115. ) {
  116. // IIS, might be encoded, see below; also prevent XSS
  117. $PHP_AUTH_USER = PMA_getenv('HTTP_AUTHORIZATION');
  118. } elseif (PMA_getenv('Authorization')) {
  119. // FastCGI, might be encoded, see below
  120. $PHP_AUTH_USER = PMA_getenv('Authorization');
  121. }
  122. }
  123. // Grabs the $PHP_AUTH_PW variable whatever are the values of the
  124. // 'register_globals' and the 'variables_order' directives
  125. if (empty($PHP_AUTH_PW)) {
  126. if (PMA_getenv('PHP_AUTH_PW')) {
  127. $PHP_AUTH_PW = PMA_getenv('PHP_AUTH_PW');
  128. } elseif (PMA_getenv('REMOTE_PASSWORD')) {
  129. // Apache/CGI
  130. $PHP_AUTH_PW = PMA_getenv('REMOTE_PASSWORD');
  131. } elseif (PMA_getenv('AUTH_PASSWORD')) {
  132. // WebSite Professional
  133. $PHP_AUTH_PW = PMA_getenv('AUTH_PASSWORD');
  134. }
  135. }
  136. // Decode possibly encoded information (used by IIS/CGI/FastCGI)
  137. // (do not use explode() because a user might have a colon in his password
  138. if (strcmp(substr($PHP_AUTH_USER, 0, 6), 'Basic ') == 0) {
  139. $usr_pass = base64_decode(substr($PHP_AUTH_USER, 6));
  140. if (! empty($usr_pass)) {
  141. $colon = strpos($usr_pass, ':');
  142. if ($colon) {
  143. $PHP_AUTH_USER = substr($usr_pass, 0, $colon);
  144. $PHP_AUTH_PW = substr($usr_pass, $colon + 1);
  145. }
  146. unset($colon);
  147. }
  148. unset($usr_pass);
  149. }
  150. // sanitize username
  151. $PHP_AUTH_USER = PMA_sanitizeMySQLUser($PHP_AUTH_USER);
  152. // User logged out -> ensure the new username is not the same
  153. $old_usr = isset($_REQUEST['old_usr']) ? $_REQUEST['old_usr'] : '';
  154. if (! empty($old_usr)
  155. && (isset($PHP_AUTH_USER) && hash_equals($old_usr, $PHP_AUTH_USER))
  156. ) {
  157. $PHP_AUTH_USER = '';
  158. // -> delete user's choices that were stored in session
  159. session_destroy();
  160. }
  161. // Returns whether we get authentication settings or not
  162. if (empty($PHP_AUTH_USER)) {
  163. return false;
  164. } else {
  165. return true;
  166. }
  167. }
  168. /**
  169. * Set the user and password after last checkings if required
  170. *
  171. * @global array the valid servers settings
  172. * @global integer the id of the current server
  173. * @global array the current server settings
  174. * @global string the current username
  175. * @global string the current password
  176. *
  177. * @return boolean always true
  178. */
  179. public function authSetUser()
  180. {
  181. global $cfg, $server;
  182. global $PHP_AUTH_USER, $PHP_AUTH_PW;
  183. // Ensures valid authentication mode, 'only_db', bookmark database and
  184. // table names and relation table name are used
  185. if (! hash_equals($cfg['Server']['user'], $PHP_AUTH_USER)) {
  186. $servers_cnt = count($cfg['Servers']);
  187. for ($i = 1; $i <= $servers_cnt; $i++) {
  188. if (isset($cfg['Servers'][$i])
  189. && ($cfg['Servers'][$i]['host'] == $cfg['Server']['host']
  190. && hash_equals($cfg['Servers'][$i]['user'], $PHP_AUTH_USER))
  191. ) {
  192. $server = $i;
  193. $cfg['Server'] = $cfg['Servers'][$i];
  194. break;
  195. }
  196. } // end for
  197. } // end if
  198. $cfg['Server']['user'] = $PHP_AUTH_USER;
  199. $cfg['Server']['password'] = $PHP_AUTH_PW;
  200. // Avoid showing the password in phpinfo()'s output
  201. unset($GLOBALS['PHP_AUTH_PW']);
  202. unset($_SERVER['PHP_AUTH_PW']);
  203. return true;
  204. }
  205. /**
  206. * User is not allowed to login to MySQL -> authentication failed
  207. *
  208. * @return boolean always true (no return indeed)
  209. */
  210. public function authFails()
  211. {
  212. $error = PMA_DBI_getError();
  213. if ($error && $GLOBALS['errno'] != 1045) {
  214. PMA_fatalError($error);
  215. } else {
  216. $this->auth();
  217. return true;
  218. }
  219. }
  220. /**
  221. * This method is called when any PluginManager to which the observer
  222. * is attached calls PluginManager::notify()
  223. *
  224. * @param SplSubject $subject The PluginManager notifying the observer
  225. * of an update.
  226. *
  227. * @return void
  228. */
  229. public function update (SplSubject $subject)
  230. {
  231. }
  232. }