| 1 |
<?php
|
| 2 |
// $Id: httpauth.module,v 1.18 2008/06/27 12:51:57 naquah Exp $
|
| 3 |
// Copyright (c) 2006-2008 Dennis Stevense, see LICENSE.txt for more information.
|
| 4 |
|
| 5 |
/**
|
| 6 |
* Implementation of hook_help().
|
| 7 |
*/
|
| 8 |
function httpauth_help($page, $arg) {
|
| 9 |
switch ($page) {
|
| 10 |
case 'admin/help#httpauth':
|
| 11 |
return "<p>". t('Allows users to authenticate using HTTP.') ."</p>\n";
|
| 12 |
}
|
| 13 |
}
|
| 14 |
|
| 15 |
/**
|
| 16 |
* Implementation of hook_perm().
|
| 17 |
*/
|
| 18 |
function httpauth_perm() {
|
| 19 |
return array('administer http authentication');
|
| 20 |
}
|
| 21 |
|
| 22 |
/**
|
| 23 |
* Implementation of hook_menu().
|
| 24 |
*/
|
| 25 |
function httpauth_menu() {
|
| 26 |
$items = array();
|
| 27 |
|
| 28 |
$items['httpauth'] = array(
|
| 29 |
'page callback' => 'httpauth_callback',
|
| 30 |
'access callback' => 'variable_get',
|
| 31 |
'access arguments' => array('httpauth_status', FALSE),
|
| 32 |
'type' => MENU_CALLBACK,
|
| 33 |
);
|
| 34 |
|
| 35 |
$items['admin/settings/httpauth'] = array(
|
| 36 |
'title' => 'HTTP authentication',
|
| 37 |
'page callback' => 'drupal_get_form',
|
| 38 |
'page arguments' => array('httpauth_settings'),
|
| 39 |
'access arguments' => array('administer http authentication'),
|
| 40 |
);
|
| 41 |
|
| 42 |
return $items;
|
| 43 |
}
|
| 44 |
|
| 45 |
/**
|
| 46 |
* Callback for httpauth. Usually called by drupal_access_denied() through the site_403 variable.
|
| 47 |
*/
|
| 48 |
function httpauth_callback() {
|
| 49 |
global $user;
|
| 50 |
|
| 51 |
// Is this an anonymous user?
|
| 52 |
if (!$user->uid) {
|
| 53 |
// Get the current path from $_REQUEST['destination'], drupal_access_denied() put it there.
|
| 54 |
$path = drupal_get_path_alias($_REQUEST['destination']);
|
| 55 |
|
| 56 |
// This pattern was taken from block_list().
|
| 57 |
$pattern = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote(variable_get('httpauth_pages', ''), '/')) .')$/';
|
| 58 |
|
| 59 |
// Do we need to promote HTTP authentication on this path?
|
| 60 |
if (preg_match($pattern, $path)) {
|
| 61 |
httpauth_unauthorized();
|
| 62 |
}
|
| 63 |
}
|
| 64 |
|
| 65 |
// Do what drupal_access_denied() would've done if we wouldn't've been called.
|
| 66 |
menu_set_active_item('');
|
| 67 |
}
|
| 68 |
|
| 69 |
/**
|
| 70 |
* Callback for the settings page.
|
| 71 |
*/
|
| 72 |
function httpauth_settings() {
|
| 73 |
$form['httpauth_status'] = array('#type' => 'checkbox', '#title' => t('Enable HTTP authentication.'), '#default_value' => variable_get('httpauth_status', FALSE), '#description' => t('<strong>Note:</strong> when you enable HTTP authentication, !the-setting will be modified. When you disable it again, the setting will be restored.', array('!the-setting' => l(t('the 403 (access denied) page setting'), 'admin/settings/error-reporting'))));
|
| 74 |
|
| 75 |
$form['httpauth_pages'] = array('#type' => 'textarea', '#title' => t('Promote HTTP authentication on pages'), '#default_value' => variable_get('httpauth_pages', ''), '#description' => t('On which pages to promote HTTP authentication, if an anonymous user stumbles upon an access denied page. Enter one page per line as a Drupal path. The * character is a wildcard.'));
|
| 76 |
|
| 77 |
$form = system_settings_form($form);
|
| 78 |
$form['#submit'][] = 'httpauth_settings_form_submit';
|
| 79 |
|
| 80 |
return $form;
|
| 81 |
}
|
| 82 |
|
| 83 |
/**
|
| 84 |
* Invoked when this modules's settings are changed.
|
| 85 |
*/
|
| 86 |
function httpauth_settings_form_submit($form, &$form_state) {
|
| 87 |
httpauth_set_site_403();
|
| 88 |
}
|
| 89 |
|
| 90 |
/**
|
| 91 |
* Sets the site_403 variable to the appropriate path.
|
| 92 |
*
|
| 93 |
* @param $disable
|
| 94 |
* If TRUE, the site_403 variable will be restored regardless of the HTTP
|
| 95 |
* authentication status.
|
| 96 |
*/
|
| 97 |
function httpauth_set_site_403($disable = FALSE) {
|
| 98 |
$site_403 = variable_get('site_403', '');
|
| 99 |
|
| 100 |
if (!$disable && variable_get('httpauth_status', FALSE)) {
|
| 101 |
if ($site_403 != 'httpauth') {
|
| 102 |
// Save original path.
|
| 103 |
variable_set('httpauth_site_403', $site_403);
|
| 104 |
// Set the path to 'httpauth' to intercept access denied pages.
|
| 105 |
variable_set('site_403', 'httpauth');
|
| 106 |
}
|
| 107 |
}
|
| 108 |
else if ($site_403 == 'httpauth') {
|
| 109 |
// Restore the original path.
|
| 110 |
$original = variable_get('httpauth_site_403', '');
|
| 111 |
variable_set('site_403', $original);
|
| 112 |
}
|
| 113 |
}
|
| 114 |
|
| 115 |
/**
|
| 116 |
* Implementation of hook_boot().
|
| 117 |
*/
|
| 118 |
function httpauth_boot() {
|
| 119 |
// Return if HTTP authentication is disabled.
|
| 120 |
if (!variable_get('httpauth_status', FALSE)) {
|
| 121 |
return;
|
| 122 |
}
|
| 123 |
|
| 124 |
// Load credentials.
|
| 125 |
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
|
| 126 |
$name = $_SERVER['PHP_AUTH_USER'];
|
| 127 |
$pass = $_SERVER['PHP_AUTH_PW'];
|
| 128 |
}
|
| 129 |
else if (isset($_GET['HTTP_AUTHORIZATION'])) {
|
| 130 |
list($name, $pass) = httpauth_parse($_GET['HTTP_AUTHORIZATION']);
|
| 131 |
}
|
| 132 |
|
| 133 |
if (isset($name) && isset($pass)) {
|
| 134 |
global $user;
|
| 135 |
|
| 136 |
// Abort if the user with the provided credentials is already logged in.
|
| 137 |
if ($user->uid && strcasecmp($user->name, $name) == 0) {
|
| 138 |
return;
|
| 139 |
}
|
| 140 |
|
| 141 |
require_once('includes/form.inc');
|
| 142 |
drupal_load('module', 'user');
|
| 143 |
if (user_is_blocked($name) || drupal_is_denied('user', $name)) {
|
| 144 |
httpauth_unauthorized();
|
| 145 |
exit;
|
| 146 |
}
|
| 147 |
user_authenticate(array('name' => $name, 'pass' => $pass));
|
| 148 |
|
| 149 |
// Was authentication successful?
|
| 150 |
if ($user->uid) {
|
| 151 |
// If caching is enabled, 'fork' the current request.
|
| 152 |
if (variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED) {
|
| 153 |
// Continue invocation of hook_boot() for modules coming after httpauth.
|
| 154 |
$invoke_hook = FALSE;
|
| 155 |
foreach (module_list(TRUE, TRUE) as $module) {
|
| 156 |
if ($invoke_hook) {
|
| 157 |
drupal_load('module', $module);
|
| 158 |
module_invoke($module, $hook);
|
| 159 |
}
|
| 160 |
else if ($module == 'httpauth') {
|
| 161 |
$invoke_hook = TRUE;
|
| 162 |
}
|
| 163 |
}
|
| 164 |
// Call drupal_page_header(), just like _drupal_bootstrap() would.
|
| 165 |
drupal_page_header();
|
| 166 |
// Fork the request, bootstrapping will continue in next phase.
|
| 167 |
include('./index.php');
|
| 168 |
// Don't continue the original request.
|
| 169 |
exit();
|
| 170 |
}
|
| 171 |
}
|
| 172 |
else {
|
| 173 |
// We need common.inc for t(), and theme.inc for theme() (called indirectly by t()).
|
| 174 |
require_once('includes/common.inc');
|
| 175 |
require_once('includes/theme.inc');
|
| 176 |
|
| 177 |
watchdog('user', 'Login attempt using HTTP authentication failed for %user.', array('%user' => $name));
|
| 178 |
|
| 179 |
httpauth_unauthorized();
|
| 180 |
exit();
|
| 181 |
}
|
| 182 |
}
|
| 183 |
// Force authentication when requested to do so.
|
| 184 |
else if (isset($_GET['authenticate'])) {
|
| 185 |
httpauth_unauthorized();
|
| 186 |
exit();
|
| 187 |
}
|
| 188 |
}
|
| 189 |
|
| 190 |
/**
|
| 191 |
* Set 401 Unauthorized status and WWW-Authenticate header.
|
| 192 |
*/
|
| 193 |
function httpauth_unauthorized() {
|
| 194 |
require_once('includes/common.inc');
|
| 195 |
require_once('includes/unicode.inc');
|
| 196 |
|
| 197 |
$site_name = trim(variable_get('site_name', 'drupal'));
|
| 198 |
$realm = mime_header_encode($site_name);
|
| 199 |
|
| 200 |
drupal_set_header("HTTP/1.0 401 Unauthorized");
|
| 201 |
drupal_set_header("WWW-Authenticate: Basic realm=\"$realm\"");
|
| 202 |
}
|
| 203 |
|
| 204 |
/**
|
| 205 |
* Parse an HTTP authorization header.
|
| 206 |
*/
|
| 207 |
function httpauth_parse($header) {
|
| 208 |
list($type, $credentials) = split(' ', $header);
|
| 209 |
if ($type == 'Basic') {
|
| 210 |
return explode(':', base64_decode($credentials));
|
| 211 |
}
|
| 212 |
}
|