/[drupal]/contributions/modules/securesite/securesite.inc
ViewVC logotype

Contents of /contributions/modules/securesite/securesite.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.30 - (show annotations) (download) (as text)
Wed Oct 29 22:20:36 2008 UTC (12 months, 4 weeks ago) by darrenoh
Branch: MAIN
CVS Tags: DRUPAL-6--2-0, HEAD
Branch point for: DRUPAL-6--2
Changes since 1.29: +7 -3 lines
File MIME type: text/x-php
Eliminated cron.php bypass.
1 <?php
2 // $Id: securesite.inc,v 1.29 2008/10/29 21:03:08 darrenoh Exp $
3
4 /**
5 * @file securesite.inc
6 *
7 * Secure Site log-in functions
8 */
9
10 /**
11 * Boot with selected authentication mechanism.
12 */
13 function _securesite_boot($type) {
14 global $user;
15 switch ($type) {
16 case SECURESITE_DIGEST:
17 $parts = explode(',', trim($_SERVER['PHP_AUTH_DIGEST']));
18 $edit = array();
19 foreach ($parts as $part) {
20 if (!empty($part)) {
21 list($key, $value) = explode('=', trim($part), 2);
22 $key = $key == 'username' ? 'name' : $key;
23 $edit[$key] = trim($value, '"');
24 }
25 }
26 $function = '_securesite_digest_auth';
27 break;
28 case SECURESITE_BASIC:
29 $edit['name'] = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
30 $edit['pass'] = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
31 $function = '_securesite_plain_auth';
32 break;
33 case SECURESITE_FORM:
34 if (!empty($_POST['openid_identifier'])) {
35 openid_begin($_POST['openid_identifier'], $_POST['openid.return_to']);
36 }
37 $edit = array('name' => $_POST['name'], 'pass' => $_POST['pass']);
38 $function = '_securesite_plain_auth';
39 break;
40 }
41 // Are credentials different from current user?
42 if ((!isset($user->name) || $edit['name'] !== $user->name) && (!isset($_SESSION['securesite_guest']) || $edit['name'] !== $_SESSION['securesite_guest'])) {
43 $function($edit);
44 }
45 }
46
47 /**
48 * Menu callback; handle restricted pages.
49 */
50 function _securesite_403() {
51 global $user;
52 if (empty($user->uid) && !isset($_SESSION['securesite_guest']) && $_GET['q'] != 'logout') {
53 _securesite_dialog(array_pop(variable_get('securesite_type', array(SECURESITE_BASIC))));
54 }
55 else {
56 $path = drupal_get_normal_path(variable_get('securesite_403', ''));
57 menu_set_active_item($path);
58 return menu_execute_active_handler($path);
59 }
60 }
61
62 /**
63 * Perform digest authentication.
64 */
65 function _securesite_digest_auth($edit) {
66 global $user;
67 $realm = variable_get('securesite_realm', variable_get('site_name', 'Drupal'));
68 $header = _securesite_digest_validate($status, array('data' => $_SERVER['PHP_AUTH_DIGEST'], 'method' => $_SERVER['REQUEST_METHOD'], 'uri' => request_uri(), 'realm' => $realm));
69 $account = user_load(array('name' => $edit['name'], 'status' => 1));
70 if (empty($account->uid)) {
71 // Not a registered user. See if we have guest user credentials.
72 switch ($status) {
73 case 1:
74 drupal_set_header('HTTP/1.1 400 Bad Request');
75 _securesite_dialog(array_pop(variable_get('securesite_type', array(SECURESITE_BASIC))));
76 break;
77 case 0:
78 // Password is correct. Log user in.
79 drupal_set_header($header);
80 $edit['pass'] = variable_get('securesite_guest_pass', '');
81 default:
82 _securesite_guest_login($edit);
83 break;
84 }
85 }
86 else {
87 switch ($status) {
88 case 0:
89 // Password is correct. Log user in.
90 $user = $account;
91 user_authenticate_finalize($edit);
92 drupal_set_header($header);
93 _securesite_user_login();
94 break;
95 case 2:
96 // Password not stored. Request credentials using next most secure authentication method.
97 $mechanism = _securesite_mechanism();
98 $types = variable_get('securesite_type', array(SECURESITE_BASIC));
99 rsort($types);
100 foreach ($types as $type) {
101 if ($type < $mechanism) {
102 break;
103 }
104 }
105 watchdog('user', 'Secure log-in failed for %user.', array('%user' => $edit['name']));
106 drupal_set_message(t('Secure log-in failed. Please try again.'), 'error');
107 _securesite_dialog($type);
108 break;
109 case 1:
110 drupal_set_header('HTTP/1.1 400 Bad Request');
111 default:
112 // Authentication failed. Request credentials using most secure authentication method.
113 watchdog('user', 'Log-in attempt failed for %user.', array('%user' => $edit['name']));
114 drupal_set_message(t('Unrecognized user name and/or password.'), 'error');
115 _securesite_dialog(array_pop(variable_get('securesite_type', array(SECURESITE_BASIC))));
116 break;
117 }
118 }
119 }
120
121 /**
122 * Get the result of digest validation.
123 *
124 * @param $status: Will be set to the return status of the validation script
125 * @param $edit: An array of parameters to pass to the validation script
126 * @return
127 * An HTTP header string.
128 */
129 function _securesite_digest_validate(&$status, $edit = NULL) {
130 static $header;
131 if (isset($edit)) {
132 if (is_array($edit)) {
133 $values = array();
134 foreach ($edit as $key => $value) {
135 $values[] = escapeshellarg("$key=$value");
136 }
137 $script = variable_get('securesite_digest_script', drupal_get_path('module', 'securesite') .'/digest_md5/digest_md5.php');
138 $response = exec($script .' '. implode(' ', $values), $output, $status);
139 if (isset($edit['data']) && empty($status)) {
140 $header = "Authentication-Info: $response";
141 }
142 else {
143 $header = "WWW-Authenticate: Digest $response";
144 }
145 }
146 else {
147 $header = $edit;
148 }
149 }
150 return $header;
151 }
152
153 /**
154 * Perform plain authentication.
155 */
156 function _securesite_plain_auth($edit) {
157 global $user;
158 $account = user_load(array('name' => $edit['name'], 'status' => 1));
159 if (empty($account->uid)) {
160 // Not a registered user. See if we have guest user credentials.
161 _securesite_guest_login($edit);
162 }
163 else {
164 // The LDAP auth module can't use the regular external user log-in system, so we
165 // have to call its log-in function directly.
166 if (module_exists('ldapauth')) {
167 ldapauth_authenticate($edit);
168 }
169 else {
170 user_authenticate($edit);
171 }
172 if (!empty($user->uid)) {
173 _securesite_user_login();
174 }
175 else {
176 // Request credentials using most secure authentication method.
177 watchdog('user', 'Log-in attempt failed for %user.', array('%user' => $edit['name']));
178 drupal_set_message(t('Unrecognized user name and/or password.'), 'error');
179 _securesite_dialog(array_pop(variable_get('securesite_type', array(SECURESITE_BASIC))));
180 }
181 }
182 }
183
184 /**
185 * Log in authenticated user.
186 */
187 function _securesite_user_login() {
188 global $user;
189 if (user_access('access secured pages')) {
190 unset($_SESSION['securesite_guest']); // Clear the guest session.
191 $_SESSION['securesite_login'] = TRUE; // Mark the session so Secure Site will be triggered on log-out.
192 // Prevent a log-in/log-out loop by redirecting off the log-out page.
193 if ($_GET['q'] == 'logout') {
194 drupal_goto();
195 }
196 }
197 // Not an authorized user.
198 else {
199 // Load the anonymous user.
200 $user = drupal_anonymous_user();
201 drupal_set_message(t('Unauthorized user.'), 'error');
202 _securesite_dialog(array_pop(variable_get('securesite_type', array(SECURESITE_BASIC))));
203 }
204 }
205
206 /**
207 * Log in guest user.
208 */
209 function _securesite_guest_login($edit) {
210 $guest_name = variable_get('securesite_guest_name', '');
211 $guest_pass = variable_get('securesite_guest_pass', '');
212 // Check anonymous user permission and credentials.
213 if (user_access('access secured pages') && (empty($guest_name) || $edit['name'] == $guest_name) && (empty($guest_pass) || $edit['pass'] == $guest_pass)) {
214 // Mark this session to prevent re-login (note: guests can't log out).
215 $_SESSION['securesite_guest'] = $edit['name'];
216 $_SESSION['securesite_login'] = TRUE;
217 // Prevent a 403 error by redirecting off the logout page.
218 if ($_GET['q'] == 'logout') {
219 drupal_goto();
220 }
221 }
222 else {
223 if (empty($edit['name'])) {
224 watchdog('user', 'Log-in attempt failed for <em>anonymous</em> user.');
225 }
226 else {
227 watchdog('user', 'Log-in attempt failed for %user.', array('%user' => $edit['name']));
228 }
229 drupal_set_message(' '. t('Unrecognized user name and/or password.') ."\n ", 'error');
230 _securesite_dialog(array_pop(variable_get('securesite_type', array(SECURESITE_BASIC))));
231 }
232 }
233
234 /**
235 * Determine if Secure Site authentication should be forced.
236 */
237 function _securesite_forced() {
238 global $base_path;
239 // Do we require credentials to display this page?
240 if (php_sapi_name() == 'cli') {
241 return FALSE;
242 }
243 else {
244 switch (variable_get('securesite_enabled', SECURESITE_DISABLED)) {
245 case SECURESITE_ALWAYS:
246 return TRUE;
247 case SECURESITE_OFFLINE:
248 return variable_get('site_offline', FALSE);
249 case SECURESITE_403:
250 if (variable_get('site_403', '') != 'securesite_403') {
251 variable_set('securesite_403', variable_get('site_403', ''));
252 variable_set('site_403', 'securesite_403');
253 }
254 default:
255 return FALSE;
256 }
257 }
258 }
259
260 /**
261 * Display authentication dialog and send password reset mails.
262 */
263 function _securesite_dialog($type) {
264 global $base_path;
265 // Has the password reset form been submitted?
266 if (isset($_POST['form_id']) && $_POST['form_id'] == 'securesite_user_pass') {
267 $content = _securesite_page();
268 }
269 // Are we on a password reset page?
270 elseif (strpos($_GET['q'], 'user/reset/') === 0 || module_exists('i18n') && i18n_selection_mode() != 'off' && strpos($_GET['q'], i18n_selection_mode('params') .'/user/reset/') === 0) {
271 $args = explode('/', $_GET['q']);
272 if (module_exists('i18n') && i18n_selection_mode() != 'off' && i18n_selection_mode('params') != '') {
273 // Remove the language argument.
274 array_shift($args);
275 }
276 // The password reset function doesn't work well if it doesn't have all the
277 // required parameters or if the UID parameter isn't valid
278 if (count($args) < 5 || user_load(array('uid' => $args[2], 'status' => 1)) == FALSE) {
279 $error = t('You have tried to use an invalid one-time log-in link.');
280 $reset = variable_get('securesite_reset_form', t('Enter your user name or e-mail address.'));
281 if (empty($reset)) {
282 drupal_set_message($error, 'error');
283 $content = '';
284 }
285 else {
286 $error .= ' '. t('Please request a new one using the form below.');
287 drupal_set_message($error, 'error');
288 $content = drupal_get_form('securesite_user_pass');
289 }
290 }
291 }
292 else {
293 // Display log-in dialog.
294 switch ($type) {
295 case SECURESITE_DIGEST:
296 $header = _securesite_digest_validate($status);
297 if (empty($header)) {
298 $realm = variable_get('securesite_realm', variable_get('site_name', 'Drupal'));
299 $header = _securesite_digest_validate($status, array('realm' => $realm, 'fakerealm' => _securesite_fake_realm()));
300 }
301 if (strpos($header, 'WWW-Authenticate') === 0) {
302 drupal_set_header($header);
303 drupal_set_header('HTTP/1.1 401 Unauthorized');
304 }
305 else {
306 drupal_set_header($header);
307 }
308 $content = _securesite_page('<p>'. t('Reload the page to try logging in again.') .'</p>');
309 break;
310 case SECURESITE_BASIC:
311 drupal_set_header('WWW-Authenticate: Basic realm="'. _securesite_fake_realm() .'"');
312 drupal_set_header('HTTP/1.1 401 Unauthorized');
313 $content = _securesite_page('<p>'. t('Reload the page to try logging in again.') .'</p>');
314 break;
315 case SECURESITE_FORM:
316 // Form authentication doesn't work for cron.
317 if (request_uri() != $base_path .'cron.php') {
318 $content = _securesite_page();
319 }
320 break;
321 }
322 }
323 if (isset($content)) {
324 drupal_add_css(drupal_get_path('module', 'securesite') .'/securesite.css');
325 print theme('securesite_page', $content);
326 module_invoke_all('exit');
327 exit();
328 }
329 }
330
331 /**
332 * Opera and Internet Explorer save credentials indefinitely and will keep
333 * attempting to use them even when they have failed multiple times. We add a
334 * random string to the realm to allow users to log out.
335 */
336 function _securesite_fake_realm() {
337 $realm = variable_get('securesite_realm', variable_get('site_name', 'Drupal'));
338 $user_agent = (isset($_SERVER['HTTP_USER_AGENT']) ? strtolower($_SERVER['HTTP_USER_AGENT']) : '');
339 if ($user_agent != str_replace(array('msie', 'opera'), '', $user_agent)) {
340 $realm .= ' - '. mt_rand(10, 999);
341 }
342 return $realm;
343 }
344
345 /**
346 * Display fallback HTML for HTTP authentication dialogs. Safari will not load
347 * this. Opera will not load this after log-out unless the page has been
348 * reloaded and the authentication dialog has been displayed twice.
349 */
350 function _securesite_page($message = NULL) {
351 $reset = variable_get('securesite_reset_form', t('Enter your user name or e-mail address.'));
352 if (in_array(SECURESITE_FORM, variable_get('securesite_type', array(SECURESITE_BASIC)))) {
353 $output = drupal_get_form('securesite_user_login');
354 $output .= empty($reset) ? '' : "<hr />\n". drupal_get_form('securesite_user_pass');
355 }
356 else {
357 if (!empty($reset) && _securesite_forced()) {
358 $output = drupal_get_form('securesite_user_pass');
359 }
360 else {
361 $output = $message;
362 }
363 }
364 return $output;
365 }
366
367 /**
368 * Process variables for securesite-page.tpl.php
369 *
370 * The $variables array contains the following arguments:
371 * - $messages
372 *
373 * @see securesite-page.tpl.php
374 */
375 function template_preprocess_securesite_page(&$variables) {
376 $variables['messages'] = theme('status_messages');
377 }
378
379 /**
380 * We use our own version of the log-in form for theming. We do not use the
381 * default validate and submit functions because we may allow anonymous users.
382 *
383 * @ingroup forms
384 * @see user_login()
385 */
386 function securesite_user_login() {
387 $form['name'] = array(
388 '#type' => 'textfield',
389 '#title' => t('User name'),
390 '#maxlength' => USERNAME_MAX_LENGTH,
391 '#size' => 15,
392 );
393 $form['pass'] = array(
394 '#type' => 'password',
395 '#title' => t('Password'),
396 '#maxlength' => 60,
397 '#size' => 15,
398 );
399 $form['submit'] = array(
400 '#type' => 'submit',
401 '#value' => t('Log in'),
402 );
403 if (module_exists('openid')) {
404 global $base_path;
405 $style = '<style type="text/css" media="all">'."\n".
406 '#securesite-user-login li.openid-link {'."\n".
407 ' background:transparent url('. $base_path . drupal_get_path('module', 'openid') .'/login-bg.png) no-repeat scroll 1px 0.35em;'."\n".
408 '}'."\n".
409 '</style>';
410 drupal_set_html_head($style);
411 }
412 drupal_alter('form', $form, NULL, 'user_login');
413 return $form;
414 }
415
416 /**
417 * Process variables for securesite-user-login.tpl.php
418 *
419 * The $variables array contains the following arguments:
420 * - $title
421 * - $messages
422 *
423 * @see securesite-user-login.tpl.php
424 */
425 function template_preprocess_securesite_user_login(&$variables) {
426 $variables['title'] = variable_get('securesite_login_form', t('Enter your user name and password.'));
427 $variables['messages'] = '';
428 // If the reset form exists and was submitted, status messages should be displayed there.
429 $reset = variable_get('securesite_reset_form', t('Enter your user name or e-mail address.'));
430 if (empty($reset) || !isset($_POST['form_id']) || isset($_POST['form_id']) && $_POST['form_id'] != 'securesite_user_pass') {
431 $variables['messages'] = theme('status_messages');
432 }
433 }
434
435 /**
436 * We use our own version of the password reset form for theming.
437 *
438 * @ingroup forms
439 * @see user_pass_validate
440 * @see user_pass_submit
441 */
442 function securesite_user_pass() {
443 module_load_include('inc', 'user', 'user.pages');
444 $form = user_pass();
445 drupal_alter('form', $form, NULL, 'user_pass');
446 $form['#redirect'] = FALSE;
447 $form['#validate'][] = 'user_pass_validate';
448 $form['#submit'][] = 'user_pass_submit';
449 return $form;
450 }
451
452 /**
453 * Process variables for securesite-user-pass.tpl.php
454 *
455 * The $variables array contains the following arguments:
456 * - $title
457 * - $messages
458 *
459 * @see securesite-user-pass.tpl.php
460 */
461 function template_preprocess_securesite_user_pass(&$variables) {
462 $variables['title'] = variable_get('securesite_reset_form', t('Enter your user name or e-mail address.'));
463 $variables['messages'] = theme('status_messages');
464 $variables['form']['name']['#required'] = FALSE;
465 }
466

  ViewVC Help
Powered by ViewVC 1.1.2