securesite.module in Secure Site 6
Same filename and directory in other branches
Secure Site contrib module
Secure Site allows the use of HTTP Auth to secure Drupal sites
File
securesite.moduleView source
<?php
/**
* @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 secured pages',
);
}
/**
* Implementation of hook_menu()
*/
function securesite_menu() {
$items['admin/settings/securesite'] = array(
'title' => 'Secure Site',
'description' => 'Enables HTTP Auth security or an HTML form to restrict site access.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'securesite_admin_settings',
),
'access arguments' => array(
'administer site configuration',
),
'file' => 'securesite.admin.inc',
);
return $items;
}
/**
* Implementation of hook_boot()
*
* This is where Secure Site does most of its processing
*
* 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_boot() {
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', '');
// Step #1: Process conditions that bypass Secure Site authentication
if (!$securesite_enabled || $securesite_enabled == SECURESITE_AUTH_ALT || php_sapi_name() == 'cli' || request_uri() == $base_path . 'cron.php' || $user->uid == 1 || !empty($guest_name) && (isset($_SESSION['securesite_guest']) ? $_SESSION['securesite_guest'] : '')) {
return;
}
// Do a full bootstrap since Secure Site uses many functions throughout Core,
// such as path.inc and user.module functions, t(), and theme()
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
// This has to be after a full bootstrap
if (_securesite_filter_check(isset($_GET['q']) ? $_GET['q'] : '') || $user->uid && user_access('access secured pages')) {
// User is logged in and has privileges to access secured pages
return;
}
// Prevent a login/logout loop by redirecting off the logout page
if (strpos(request_uri(), $base_path . 'logout') === 0) {
drupal_goto('<front>');
}
// 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,
))) {
// Sanity-checking complete, now let user_pass_reset() and the menu
// system handle it
return;
}
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');
}
}
// Step #3: Set up variables
if ($securesite_enabled == SECURESITE_FORM && !empty($_POST['edit'])) {
$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'];
}
}
// Step #4: If needed, ask user for credentials
if ((empty($edit['name']) || empty($edit['pass'])) && $user->uid == 0) {
_securesite_user_auth();
}
// 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;
$_SESSION['securesite_login'] = TRUE;
// Redirect to prevent some caching problems
drupal_goto($_GET['q']);
}
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(array(
'name' => $edit['name'],
'pass' => $edit['pass'],
));
}
// Step #7: Process login attempt
if ((isset($account->uid) ? $account->uid : FALSE) && user_access('access secured pages', $account)) {
// Mark the session so Secure Site will be triggered on logout
$_SESSION['securesite_login'] = TRUE;
// Redirect to prevent some caching problems
drupal_goto($_GET['q']);
}
else {
// Login failed
if (!empty($edit['name'])) {
watchdog('user', 'Login attempt failed for %user.', array(
'%user' => $edit['name'],
));
}
else {
watchdog('user', 'Login attempt failed for <em>anonymous</em> user.', array(
'%user' => $edit['name'],
));
}
_securesite_user_auth();
}
}
/**
* 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' && variable_get('securesite_enabled', SECURESITE_DISABLED) == SECURESITE_AUTH && (isset($_SESSION['securesite_login']) ? $_SESSION['securesite_login'] : FALSE)) {
// Load the anonymous user
$user = drupal_anonymous_user();
// Clear stored credentials
_securesite_user_auth();
}
}
/**
* Display authentication dialog and send password reset mails
*/
function _securesite_user_auth() {
global $base_url;
module_load_include('inc', 'securesite');
$securesite_enabled = variable_get('securesite_enabled', SECURESITE_DISABLED);
$content = '';
// 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');
}
// 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 == SECURESITE_FORM) {
$content .= _securesite_login_form();
}
$content .= _securesite_request_form();
// 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 = isset($_SERVER['HTTP_USER_AGENT']) ? strtolower($_SERVER['HTTP_USER_AGENT']) : '';
foreach ($browsers as $browser) {
if (strpos($user_agent, $browser) !== FALSE) {
$realm .= ' - ' . mt_rand(10, 999);
break;
}
}
header('WWW-Authenticate: Basic realm="' . $realm . '"');
header('HTTP/1.0 401 Unauthorized');
}
// Step #4: Show the login form and/or password request form if user cancels
// HTTP Auth dialog
_securesite_dialog_page($content);
module_invoke_all('exit', request_uri());
session_write_close();
exit;
}
/**
* 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($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
$alias = drupal_get_path_alias($path);
$regexp = '/^(' . preg_replace(array(
'/(\\r\\n?|\\n)/',
'/\\\\\\*/',
'/(^|\\|)\\\\<front\\\\>($|\\|)/',
), array(
'|',
'.*',
'\\1' . preg_quote(variable_get('site_frontpage', 'node'), '/') . '\\2',
), preg_quote($pages, '/')) . ')$/';
$page_match = preg_match($regexp, $alias);
// Check normal paths if the alias lookup fails to match
if (!$page_match) {
$alias = drupal_get_normal_path($path);
$page_match = preg_match($regexp, $alias);
}
// Whitelist or blacklist?
if (variable_get('securesite_filter_pages_type', SECURESITE_WHITELIST) == !$page_match) {
return TRUE;
}
return FALSE;
}
/**
* Implementation of hook_mail()
*/
function securesite_mail($key, &$message, $params) {
// Ignoring $key for now, since there's only one type of mail sent by Secure Site
$message['subject'] = $params['subject'];
$message['body'] = $params['body'];
}
Functions
Name | Description |
---|---|
securesite_boot | Implementation of hook_boot() |
securesite_mail | Implementation of hook_mail() |
securesite_menu | Implementation of hook_menu() |
securesite_perm | Implementation of hook_perm() |
securesite_user | Implementation of hook_user() |
_securesite_filter_check | Check if pages should bypass Secure Site |
_securesite_user_auth | Display authentication dialog and send password reset mails |
Constants
Name | Description |
---|---|
SECURESITE_AUTH | Secure Site status: Enabled with Web browser HTTP Auth security |
SECURESITE_AUTH_ALT | Secure Site status: Enabled with Web browser HTTP Auth security using the alterative method (deprecated) |
SECURESITE_BLACKLIST | Secure Site bypass: Only the listed pages do require authentication |
SECURESITE_DISABLED | Secure Site status: Disabled |
SECURESITE_FORM | Secure Site status: Enabled with HTML login form |
SECURESITE_WHITELIST | Secure Site bypass: Only the listed pages don't require authentication |