Index: securesite.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/securesite/securesite.inc,v retrieving revision 1.2.2.10 diff -u -w -B -F^f -r1.2.2.10 securesite.inc --- securesite.inc 9 May 2007 22:33:20 -0000 1.2.2.10 +++ securesite.inc 7 Oct 2008 13:08:42 -0000 @@ -2,62 +2,151 @@ // $Id: securesite.inc,v 1.2.2.10 2007/05/09 22:33:20 unconed Exp $ /** - * Returns complete form for login. + * @file + * Support functions for the Secure Site contrib module + */ + +/** + * Returns complete form for login when using the HTML form + * + * @return + * HTML used in the Secure Site dialog when the HTML login form is in use */ function _securesite_login_form() { - return '

'. variable_get('securesite_login_form', 'Enter your '. variable_get('site_name', 'local') .' username and password.') .'

'. theme_status_messages() . -'
-
- -
'; + return "\n

". t('Login') .'

+
'. variable_get('securesite_login_form', t('

Enter your username and password.

')) . (!isset($_POST['securesite_request_form']) ? theme('status_messages') : '') .'
+
+

+

+

+
+ +'; } /** - * Returns complete form for password reset request -if- securesite_request_form var exists. + * Returns complete form for password reset request (if enabled) + * + * @return + * HTML used in the Secure Site dialog when the HTTP Auth dialog is cancelled */ function _securesite_request_form() { - if ($formMsg = variable_get('securesite_request_form', t('Enter your username or your e-mail address.'))) { - return '

'. $formMsg .'

'. theme_status_messages() .'
-
- -
'; + $securesite_enabled = variable_get('securesite_enabled', SECURESITE_DISABLED); + $output = ''; + + if ($form_msg = variable_get('securesite_request_form', t('

Enter your username or e-mail address.

'))) { + if ($securesite_enabled == SECURESITE_FORM) { + // Only output the HR if also outputting the login form + $output = "
\n\n "; + } + + $output .= "\n

". t('Password Reset') .'

+
'. $form_msg .'
+ '. theme('status_messages') .' +
+

+

+

+
+ +'; } - return ''; + else if ($securesite_enabled == SECURESITE_AUTH) { + // If password reset is disabled and the login form isn't being used, + // output a message to the user informing them how to login + $output = theme('status_messages') .'

'. t('Reload the page to try logging in again.') ."

\n"; + } + + return $output; } /** - * Print HTML dialog page for securesite. + * Print HTML dialog page for Secure Site + * + * @param $content + * HTML to output for the login and/or password reset form */ function _securesite_dialog_page($content) { + $theme_path = drupal_get_path('theme', variable_get('theme_default', 'garland')); + $dialog_file = '/securesite-dialog.tpl.php'; - // Display themed dialog - $themes = list_themes(); - $theme = variable_get('theme_default', 'bluemarine'); - $dialog_file = dirname($themes[$theme]->filename) .'/securesite-dialog.tpl.php'; - if (file_exists($dialog_file)) { - include_once($dialog_file); + if (file_exists($theme_path . $dialog_file)) { + include_once($theme_path . $dialog_file); } else { - // Display default dialog - print ' - - -'. variable_get('site_name', 'drupal') .' - - -
'. $content .'
-'; + include_once(drupal_get_path('module', 'securesite') . $dialog_file); } } +/** + * Process password reset requests + * + * @param $edit + * Username or e-mail address of user requesting password reset + */ +function _securesite_password_reset($edit = array()) { + global $base_url; + + // Only look-up information if input was given + if ($edit['name'] || $edit['mail']) { + // User must have an active account + $load['status'] = 1; + + // Only create array keys/values if something was entered, otherwise + // user_load() will fail + if (!empty($edit['name'])) { + $load['name'] = $edit['name']; + } + + if (!empty($edit['mail'])) { + $load['mail'] = $edit['mail']; + } + + // Check account information + $account = user_load($load); + + if ($account && $account->uid) { // Valid account, e-mail the user a new password + // Generate a new password for this user + $account = user_save($account, array('pass' => user_password())); + + // Mail new password + $variables = array( + '!username' => $account->name, + '!site' => variable_get('site_name', 'Drupal'), + '!login_url' => user_pass_reset_url($account), + '!uri' => $base_url, + '!uri_brief' => preg_replace('`^https?://`i', '', $base_url), + '!mailto' => $account->mail, + '!date' => format_date(time()), + '!login_uri' => url('user', NULL, NULL, TRUE), + '!edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE), + ); + $subject = _user_mail_text('pass_subject', $variables); + $body = _user_mail_text('pass_body', $variables); + $mail_success = drupal_mail('securesite-password', $account->mail, $subject, $body); + + if ($mail_success) { + watchdog('user', t('Password mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail))); + + // Exit here because presumably the user can't do anything more before + // visiting the password reset URL + _securesite_dialog_page('

'. t('Further instructions have been e-mailed to you.') ."

\n"); + session_write_close(); + module_invoke_all('exit', request_uri()); + exit(); + } + else { + // Note: At this point, the user's password has already been reset + watchdog('user', t('Error mailing password to %name at %email.', array('%name' => $account->name, '%email' => $account->mail)), WATCHDOG_ERROR); + drupal_set_message(t('Unable to send mail. Please contact the site admin.'), 'error'); + } + } + else { // Name or mail not valid or account disabled + drupal_set_message(t('Unrecognized username or e-mail address.'), 'error'); + } + } + + else { // Nothing entered + drupal_set_message(t('Unrecognized username or e-mail address.'), 'error'); + } +} Index: securesite.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/securesite/securesite.module,v retrieving revision 1.2.2.28 diff -u -w -B -F^f -r1.2.2.28 securesite.module --- securesite.module 30 Jan 2008 21:27:51 -0000 1.2.2.28 +++ securesite.module 7 Oct 2008 13:08:43 -0000 @@ -2,10 +2,52 @@ // $Id: securesite.module,v 1.2.2.28 2008/01/30 21:27:51 killes Exp $ /** - * Implementation of hook_perm(). + * @file + * Secure Site contrib module + * + * Secure Site allows the use of HTTP Auth to secure Drupal sites + */ + +/** + * Secure Site status: Disabled + */ +define('SECURESITE_DISABLED', 0); + +/** + * Secure Site status: Enabled with Web browser HTTP Auth security + */ +define('SECURESITE_AUTH', 1); + +/** + * Secure Site status: Enabled with Web browser HTTP Auth security using the + * alterative method (deprecated) + */ +define('SECURESITE_AUTH_ALT', 2); + +/** + * Secure Site status: Enabled with HTML login form + */ +define('SECURESITE_FORM', 3); + +/** + * Secure Site bypass: Only the listed pages don't require authentication + * + * @see _securesite_filter_check() + */ +define('SECURESITE_WHITELIST', 0); + +/** + * Secure Site bypass: Only the listed pages do require authentication + * + * @see _securesite_filter_check() + */ +define('SECURESITE_BLACKLIST', 1); + +/** + * Implementation of hook_perm() */ function securesite_perm() { - return array('access site'); + return array('access secured pages'); } /** @@ -13,7 +55,7 @@ function securesite_perm() { */ function securesite_help($section) { if ($section == 'admin/modules#description') { - return t('Enables HTTP-AUTH security or an HTML form to restrict site access.'); + return t('Enables HTTP Auth security or an HTML form to restrict site access.'); } } @@ -27,84 +69,93 @@ function securesite_settings() { $form['authentication'] = array( '#type' => 'fieldset', '#title' => t('Authentication'), + '#description' => t('Enable Secure Site below. Users must have the "access secured pages" permission in order to access the site once the following setting is enabled.', array('!access' => url('admin/access'))) ); $form['authentication']['securesite_enabled'] = array( '#type' => 'radios', - '#title' => t('Secure site'), - '#default_value' => variable_get('securesite_enabled', 0), + '#title' => t('Forced authentication'), + '#default_value' => variable_get('securesite_enabled', SECURESITE_DISABLED), '#options' => array( - t('Disabled'), - t('Enabled with web browser HTTP-AUTH security'), - t('Enabled with web browser HTTP-AUTH security, with browser logout workaround'), - t('Enabled with HTML login form'), + SECURESITE_DISABLED => t('Disabled'), + SECURESITE_AUTH => t('Use HTTP Auth'), + SECURESITE_FORM => t('Use HTML login form'), ), - '#description' => t('HTTP-AUTH requires PHP to be installed as an Apache module. At least one role must also have permission under access control page. The browser workaround is for when a user logs out, as all browsers manage the HTTP Auth variables differently the workaround will append to the end of the realm a random number to force the browser to clear the username and password. The workaround is only for some browsers. Without the workaround user will not be properly logged out in some browsers.', array('%access' => url('admin/access'))), + '#description' => t('HTTP Auth requires extra configuration if PHP is not installed as an Apache module. See the Known Issues section of the README.txt included with Secure Site for details.'), ); - $form['authentication']['securesite_guest_name'] = array( + $form['authentication']['securesite_realm'] = array( '#type' => 'textfield', - '#title' => t('Guest user'), - '#default_value' => variable_get('securesite_guest_name', ''), + '#title' => t('Authentication realm'), + '#default_value' => variable_get('securesite_realm', variable_get('site_name', 'Drupal')), '#length' => 30, '#maxlength' => 40, - '#description' => t('Guests can access the secured site without an account. Leave empty for no guest access'), + '#description' => t('Name to identify login area in HTTP Auth dialog'), + ); + + // Guest access + $form['guest'] = array( + '#type' => 'fieldset', + '#title' => t('Guest access'), + '#description' => t('Guest access allows unregistered (anonymous) users to view secure pages, though a username and password are still required. You can set the username and password for all anonymous users below. If left blank, guest user access will be disabled.'), ); - $form['authentication']['securesite_guest_pass'] = array( + $form['guest']['securesite_guest_name'] = array( '#type' => 'textfield', - '#title' => t('Guest password'), - '#default_value' => variable_get('securesite_guest_pass', ''), + '#title' => t('Guest user'), + '#default_value' => variable_get('securesite_guest_name', ''), '#length' => 30, '#maxlength' => 40, - '#description' => t('Leave empty for no guest access'), + '#description' => t('Leave empty to disable guest access'), ); - $form['authentication']['securesite_realm'] = array( + $form['guest']['securesite_guest_pass'] = array( '#type' => 'textfield', - '#title' => t('Authentication realm'), - '#default_value' => variable_get('securesite_realm', preg_replace('`^https?://`i', '', $base_url)), + '#title' => t('Guest password'), + '#default_value' => variable_get('securesite_guest_pass', ''), '#length' => 30, '#maxlength' => 40, - '#description' => t('Name to identify log-in area.'), + '#description' => t('Leave empty to disable guest access'), ); - // HTML log-in form settings + // HTML login form settings $form['login_form'] = array( '#type' => 'fieldset', - '#title' => t('HTML log-in form'), + '#title' => t('Customize HTML forms'), + '#description' => t('Configure the message displayed on the HTML login form (if enabled) and password reset form below.') ); $form['login_form']['securesite_login_form'] = array( '#type' => 'textarea', - '#title' => t('Message for HTML log-in form'), - '#default_value' => variable_get('securesite_login_form', t('Enter your %site username and password.', array('%site' => variable_get('site_name', 'drupal')))), + '#title' => t('Custom message for HTML login form'), + '#default_value' => variable_get('securesite_login_form', t('

Enter your username and password:

')), '#length' => 60, '#height' => 3, ); $form['login_form']['securesite_request_form'] = array( '#type' => 'textarea', - '#title' => t('Message for request password reset form'), - '#default_value' => variable_get('securesite_request_form', t('Enter your username or your e-mail address.')), + '#title' => t('Custom message for password reset form'), + '#default_value' => variable_get('securesite_request_form', t('

Enter your username or e-mail address:

')), '#length' => 60, '#height' => 3, - '#description' => t('Leave empty to not process password resets through this module.'), + '#description' => t('Leave empty to disable Secure Site\'s password reset form.'), ); - // Bypass login filter pages settings + // Bypass login settings $form['filter_pages'] = array( '#type' => 'fieldset', - '#title' => t('Bypass log-in filter'), + '#title' => t('Bypass login'), + '#description' => t('Some sites may wish to only use Secure Site for certain pages. Use the settings below to configure which pages force authentication via Secure Site. Select "On every page except the listed pages" and leave the "Pages" list empty to force authentication for all pages (this is the default configuration). The cron page is always accessible.'), ); $form['filter_pages']['securesite_filter_pages_type'] = array( '#type' => 'radios', - '#title' => t('Filter type'), - '#default_value' => variable_get('securesite_filter_pages_type', 0), + '#title' => t('Force authentication'), + '#default_value' => variable_get('securesite_filter_pages_type', SECURESITE_WHITELIST), '#options' => array( - t('Only the listed pages.'), - t('Every page except the listed pages.'), + SECURESITE_WHITELIST => t('On every page except the listed pages. Use this setting to restrict access of your entire site.'), + SECURESITE_BLACKLIST => t('Only on the listed pages. Use this setting only if you want to restrict access to certain pages, not your entire site.'), ), ); @@ -114,251 +165,274 @@ function securesite_settings() { '#default_value' => variable_get('securesite_filter_pages', ''), '#length' => 60, '#height' => 3, - '#description' => t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are 'blog' for the blog page and 'blog/*' for every personal blog."), + '#description' => t("Enter one path per line. Enter <front> for your site's front page. \"*\" acts as a wildcard. For example, enter blog for the blog page and blog/* for every personal blog."), ); return $form; } /** - * Implementation of hook_init(). + * Implementation of hook_init() + * + * This is where Secure Site does most of its processing * - * Implements the securesite authentication. + * Note: When a user is logged in, but doesn't have the 'access secured pages' + * permission, they get a normal Access Denied message */ function securesite_init() { - global $user, $base_url; - + global $user, $base_path; + $securesite_enabled = variable_get('securesite_enabled', SECURESITE_DISABLED); $guest_name = variable_get('securesite_guest_name', ''); $guest_pass = variable_get('securesite_guest_pass', ''); - $securesite_enabled = variable_get('securesite_enabled', 0); - // Ignore securesite for cron requests. - if (!$securesite_enabled || request_uri() == $base_url .'/cron.php') { + // Step #1: Process conditions that bypass Secure Site authentication + if (!$securesite_enabled // Secure Site isn't enabled + || ($securesite_enabled == SECURESITE_AUTH_ALT) // Old auth method, deprecated in 5.x-1.4 + || (php_sapi_name() == 'cli') // Running PHP from the command line, such as when using Drush + || (request_uri() == $base_path .'cron.php') // Accessing cron page + || ($user->uid == 1) // Site administrator + || ($user->uid && user_access('access secured pages')) // User is logged in and has privileges to access secured pages + || ((!empty($guest_name)) // Guest access is allowed and guest has previously logged in + && (isset($_SESSION['securesite_guest']) ? $_SESSION['securesite_guest'] : ''))) { return; } - // Create edit variables. - if ($securesite_enabled == 3 && !empty($_POST)) { - $edit = $_POST['edit']; + // Do a partial bootstrap when caching is enabled since Secure Site uses + // stuff in path.inc for the following bypass check + if (variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED) { + drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH); } - elseif ($securesite_enabled == 1 || $securesite_enabled == 2) { - $edit = array('name' => $_SERVER['PHP_AUTH_USER'], 'pass' => $_SERVER['PHP_AUTH_PW']); + + // User accessing a page in the bypass list. This has to be after a partial + // bootstrap so path.inc functions are available and $_GET['q'] is set. + if (_securesite_filter_check((isset($_GET['q']) ? $_GET['q'] : ''))) { + return; } - // Check if this page should bypass the authentication, but only if the user is not logged in. - if (!$user->uid) { - $check_name = securesite_filter_check(); - if ($check_name) { - if (!is_bool($check_name)) { - $user = user_load(array('name' => $check_name, 'status' => 1)); + // Prevent a login/logout loop by redirecting off the logout page + if (strpos(request_uri(), $base_path .'logout') === 0) { + drupal_goto(''); } - return; + + // Finish bootstrap since Secure Site uses many functions throughout Core, + // such as user.module functions, t(), and theme() + if (variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED) { + drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); + } + + // Step #2: Process password resets + if (strpos(request_uri(), $base_path .'user/reset/') === 0) { + $args = explode('/', $_GET['q']); + + // The password reset function doesn't work well if it doesn't have all the + // required parameters or if the UID parameter isn't valid + if (count($args) >= 5 && user_load(array('uid' => $args[2], 'status' => 1))) { + user_pass_reset($args[2], $args[3], $args[4], 'login'); + } + else { + drupal_set_message(t('You have tried to use an invalid one-time login link. Please request a new one using the form below.'), 'error'); } } - // Check if user is logged in. - if (($user->uid == 1) || ($user->uid && user_access('access site'))) { - return; + // Step #3: Set up variables + if ($securesite_enabled == SECURESITE_FORM && !empty($_POST)) { + $edit = $_POST['edit']; + } + elseif ($securesite_enabled == SECURESITE_AUTH) { + // PHP in CGI mode work-arounds. Sometimes, "REDIRECT_" prefixes $_SERVER + // variables. See http://www.php.net/reserved.variables + if (!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && empty($_SERVER['HTTP_AUTHORIZATION'])) { + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + } + + // Auth variables set via Rewrite rules need to be decoded + // See http://www.php.net/manual/en/features.http-auth.php#76708 + if (!empty($_SERVER['HTTP_AUTHORIZATION'])) { + list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))); + } + + // Process username and password normally. The correct $_SERVER variables + // are now set if PHP is run in CGI mode + if (isset($_SERVER['PHP_AUTH_USER'])) { + $edit['name'] = $_SERVER['PHP_AUTH_USER']; + } + + if (isset($_SERVER['PHP_AUTH_PW'])) { + $edit['pass'] = $_SERVER['PHP_AUTH_PW']; + } } - // Check if authentication is needed first. - if (!$user->uid && (empty($edit) || user_access('access site'))) { - securesite_user_auth(); + // Step #4: If needed, ask user for credentials + if ((empty($edit['name']) || empty($edit['pass'])) && ($user->uid == 0)) { + _securesite_user_auth(); } - // Check if user is a guest. - if ((!empty($guest_name) && $guest_name == $edit['name'] && $guest_pass == $edit['pass']) || $_SESSION['securesite_guest']) { - // Mark this session to prevent re-login (note: guest can't log out). + // Step #5: Check if user is a guest and log them in if they are + if (!empty($guest_name) && !empty($guest_pass) && ($guest_name == $edit['name']) && ($guest_pass == $edit['pass'])) { + // Mark this session to prevent re-login (note: guests can't logout) $_SESSION['securesite_guest'] = TRUE; - if (arg(0) != 'logout') { // only redirect if on logout page - return; + $_SESSION['securesite_login'] = TRUE; + + // Redirect to prevent some caching problems + drupal_goto($_GET['q']); } - securesite_goto(); + unset($_SESSION['securesite_guest']); // If not a guest, make sure to clear the guest session + + // Step #6: Check user's credentials + // The LDAP auth module can't use the regular external user login system, so + // we have to call its login function directly + if (function_exists('_ldapauth_user_authenticate')) { + $account = _ldapauth_user_authenticate($edit['name'], $edit['pass']); + } + else { + $account = user_authenticate($edit['name'], $edit['pass']); } unset($_SESSION['securesite_guest']); // If not a guest make sure to unset guest session. $account = user_authenticate($edit['name'], $edit['pass']); - if ($account->uid && user_access('access site', $account)) { - // Log-in is successful. + // Step #7: Process login attempt + if ((isset($account->uid) ? $account->uid : FALSE) && user_access('access secured pages', $account)) { + // Login successful $user = $account; - watchdog('user', t('Session opened for %name.', array('%name' => securesite_theme_placeholder($user->name)))); + // Mark the session so Secure Site will be triggered on logout + $_SESSION['securesite_login'] = TRUE; + + watchdog('user', t('Session opened for %name.', array('%name' => $user->name))); db_query("UPDATE {users} SET login = '%d' WHERE uid = '%s'", time(), $user->uid); user_module_invoke('login', $edit, $user); - if (arg(0) != 'logout') { // only redirect if on logout page - return; + + // Redirect to prevent some caching problems + drupal_goto($_GET['q']); } - securesite_goto(); + else { + // Login failed + if (!empty($edit['name'])) { + watchdog('user', t('Login attempt failed for %user.', array('%user' => $edit['name']))); } else { - // Log-in failed - securesite_user_auth(); + watchdog('user', t('Login attempt failed for anonymous user.', array('%user' => $edit['name']))); + } + _securesite_user_auth(); } } /** - * Implementation of hook_user(). + * Implementation of hook_user() + * + * When users logout, show the HTTP Auth dialog to make sure the HTTP Auth + * credentials are cleared + * + * @see _securesite_user_auth() */ function securesite_user($op, &$edit, &$user) { - if ($op == 'logout') { - module_invoke_all('exit', request_uri()); + if (($op == 'logout') + && (variable_get('securesite_enabled', SECURESITE_DISABLED) == SECURESITE_AUTH) + && ((isset($_SESSION['securesite_login']) ? $_SESSION['securesite_login'] : FALSE))) { + // Load the anonymous user unset($GLOBALS['user']); - $securesite_enabled = variable_get('securesite_enabled', 0); - if ($securesite_enabled == 1 || $securesite_enabled == 2) { - securesite_user_auth(); - } - else { - // redirect first to browser prevent caching problems - securesite_goto(); - } + // Clear stored credentials + _securesite_user_auth(); } } /** - * Securesite redirect. + * Display authentication dialog and send password reset mails */ -function securesite_goto() { +function _securesite_user_auth() { global $base_url; - $url = (arg(0) == 'logout' ? $base_url : request_uri()); - if (ini_get('session.use_trans_sid') && session_id() && !strstr($url, session_id())) { - $url .= (strstr($url, '?') && !strstr($url, $sid) ? '&' : '?') . session_name() . '=' . session_id(); - } - - header('Location: ' . $url); - exit; -} - -/** - * Mystery replacement for theme_placeholder in core that isn't themable and - * doesn't use check_plain for reasons unknown. - */ -function securesite_theme_placeholder($text) { - return '' . htmlspecialchars($text, ENT_QUOTES) . ''; -} - -/** - * Display authentication dialog and sends password requests. - */ -function securesite_user_auth() { - global $user, $base_url; include_once('securesite.inc'); - $edit = $_POST['edit']; - $securesite_enabled = variable_get('securesite_enabled', 0); - unset($content); + $securesite_enabled = variable_get('securesite_enabled', SECURESITE_DISABLED); + $content = ''; - // Log failed requests. - if ($_POST['securesite_login_form'] && $edit['name'] && $edit['pass']) { - watchdog('user', t('Log-in attempt failed for %name.', array('%name' => securesite_theme_placeholder($edit['name'])))); - drupal_set_message(t('Sorry. Unrecognized username or password.'), 'error'); - } - - // Set user messages. - if ($_POST['securesite_request_form'] && $edit['name'] && $edit['mail']) { - if (!$account = user_load(array('name' => $edit['name'], 'status' => 1))) { - drupal_set_message(t('Sorry. Unrecognized username or e-mail address.'), 'error'); - } - elseif (!$account = user_load(array('mail' => $edit['mail'], 'status' => 1))) { - drupal_set_message(t('Sorry. Unrecognized username or e-mail address.'), 'error'); - } + // Step #1: Check if the user attempted to submit the login form. If so, + // getting here means they didn't enter their info correctly + if (isset($_POST['securesite_login_form'])) { + drupal_set_message(t('Unrecognized username and/or password.'), 'error'); } - // E-mail a user a new password. - if ($account->uid) { - $from = variable_get('site_mail', ini_get('sendmail_from')); - - // Generate a new password for this user. - $pass = user_password(); - user_save($account, array('pass' => $pass)); - - // Mail new password. - $variables = array( - '%username' => $account->name, - '%site' => variable_get('site_name', 'drupal'), - '%login_url' => user_pass_reset_url($account), - '%uri' => $base_url, - '%uri_brief' => preg_replace('`^https?://`i', '', $base_url), - '%mailto' => $account->mail, - '%date' => format_date(time()), - '%login_uri' => url('user', NULL, NULL, TRUE), - '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE), - ); - - $subject = _user_mail_text('pass_subject', $variables); - $body = _user_mail_text('pass_body', $variables); - $headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"; - $mail_success = user_mail($account->mail, $subject, $body, $headers); - - if ($mail_success) { - watchdog('user', t('Password mailed to %name at %email.', array('%name' => securesite_theme_placeholder($account->name), '%email' => securesite_theme_placeholder($account->mail)))); - drupal_set_message(t('Your password and further instructions have been sent to your e-mail address.')); - } - else { - watchdog('user', t('Error mailing password to %name at %email.', array('%name' => securesite_theme_placeholder($account->name), '%email' => securesite_theme_placeholder($account->mail))), WATCHDOG_ERROR); - drupal_set_message(t('Unable to send mail. Please contact the site admin.', 'error')); - } - //nowhere to go!! //securesite_goto(); + // Step #2: Check if the user attempted to submit the password request form. + // If so, check if we have information for the name/mail they entered and + // send it if we do + if (isset($_POST['securesite_request_form']) && isset($_POST['edit'])) { + _securesite_password_reset($_POST['edit']); } - // Get content for dialog. - if ($securesite_enabled == 3) { - $content = _securesite_login_form(); + // Get content for dialog + if ($securesite_enabled == SECURESITE_FORM) { + $content .= _securesite_login_form(); } $content .= _securesite_request_form(); - // HTTP AUTH - if (($securesite_enabled == 1 || $securesite_enabled == 2) && !$account->uid) { - $realm = variable_get('securesite_realm', variable_get('site_name', 'drupal')); - - if ($securesite_enabled == 2) { - // Fix logout on cancel in Opera and IE - $browser_user_agent = strtolower($_SERVER['HTTP_USER_AGENT']); - if (strpos($browser_user_agent, "gecko") === FALSE) { // Firefox - $suffix = ' - '. mt_rand(10, 99); - } - else { // Opera, IE, others? - $suffix = ''; + // Step #3: If using HTTP Auth, send the appropriate headers, but only if the + // user isn't logged in and they haven't just submitted the password reset or + // login forms + if (($securesite_enabled == SECURESITE_AUTH) && empty($_POST['securesite_request_form']) && empty($_POST['securesite_login_form'])) { + $realm = variable_get('securesite_realm', variable_get('site_name', 'Drupal')); + + // If not on the home page of the site, Opera will not show the auth dialog + // the first time after logout. It will show the page displayed before + // logging out. Reloading will cause the dialog to display. Safari + // doesn't seem show the login/password request form when cancelling the + // auth dialog no matter what + $browsers = array('msie', 'opera', 'safari'); + $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']); + + foreach ($browsers as $browser) { + if (strpos($user_agent, $browser) !== FALSE) { + $realm .= ' - '. mt_rand(10, 999); + break; } - $realm .= $suffix; } header('WWW-Authenticate: Basic realm="'. $realm .'"'); header('HTTP/1.0 401 Unauthorized'); } - // Display dialog + // Step #4: Show the login form and/or password request form if user cancels + // HTTP Auth dialog _securesite_dialog_page($content); - drupal_set_title(t('Log in')); module_invoke_all('exit', request_uri()); - exit; + session_write_close(); + exit(); } /** - * Check if pages should bypass securesite. + * Check if pages should bypass Secure Site + * + * @param $path + * String containing the path to be filtered + * + * @return + * TRUE if Secure Site should be bypassed */ -function securesite_filter_check() { - - // If cache is enabled we need to load the path system - if (variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED) { - drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH); +function _securesite_filter_check($path) { + // Don't allow empty paths + if (empty($path)) { + return FALSE; } // Fetch paths to ignore $pages = variable_get('securesite_filter_pages', ''); - // Check if the current path matches the list defined by the admin. - $path = drupal_get_path_alias($_GET['q']); + // Check if the current path matches the list defined by the admin + $alias = drupal_get_path_alias($path); $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote($pages, '/')) .')$/'; - $page_match = preg_match($regexp, $path); + $page_match = preg_match($regexp, $alias); - // Check normal paths if the alias lookup fails to match. + // Check normal paths if the alias lookup fails to match if (!$page_match) { - $path = drupal_get_normal_path($_GET['q']); - $page_match = preg_match($regexp, $path); + $alias = drupal_get_normal_path($path); + $page_match = preg_match($regexp, $alias); } - return FALSE; + // Whitelist or blacklist? + if (variable_get('securesite_filter_pages_type', SECURESITE_WHITELIST) == !$page_match) { + return TRUE; } + return FALSE; +}