From 4194d32185ee02dbf6d935bb08102306d4a19d15 Mon Sep 17 00:00:00 2001 From: iarenaza Date: Sat, 14 Feb 2009 16:21:14 +0000 Subject: [PATCH] NTLM SSO: MDL-14584 Fix for several outstanding NTLM SSO issues. These include: MDL-14078: redirect() doubles the specified timeout when we haven't printed the page header and uses javascript to execute the redirect. This is interacting badly with some versions of IE and FF (at least 3.0.x Windows version) that fireup javascript timers even if we already left the page where we set those up. Just print the page header (we are printing other content anyway) to make redirect respect our timeouts. MDL-14071: All the relevant details are in the description of the bug :) MDL-14297: This is probably the same as MDL-14078 --- auth/ldap/auth.php | 56 ++++++++++++++++++++++++++++------- auth/ldap/ntlmsso_attempt.php | 10 ++++++- auth/ldap/ntlmsso_finish.php | 8 ++++- 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/auth/ldap/auth.php b/auth/ldap/auth.php index 3616ee4eed..7376facd2a 100644 --- a/auth/ldap/auth.php +++ b/auth/ldap/auth.php @@ -1769,16 +1769,45 @@ class auth_plugin_ldap extends auth_plugin_base { * */ function loginpage_hook() { - global $CFG; + global $CFG, $SESSION; + + if (($_SERVER['REQUEST_METHOD'] === 'GET' // Only on initial GET of loginpage + || ($_SERVER['REQUEST_METHOD'] === 'POST' + && (get_referer() != strip_querystring(qualified_me())))) + // Or when POSTed from another place + // See MDL-14071 + && !empty($this->config->ntlmsso_enabled) // SSO enabled + && !empty($this->config->ntlmsso_subnet) // have a subnet to test for + && empty($_GET['authldap_skipntlmsso']) // haven't failed it yet + && (isguestuser() || !isloggedin()) // guestuser or not-logged-in users + && address_in_subnet($_SERVER['REMOTE_ADDR'], $this->config->ntlmsso_subnet)) { + + // First, let's remember where we were trying to get to before we got here + if (empty($SESSION->wantsurl)) { + $SESSION->wantsurl = (array_key_exists('HTTP_REFERER', $_SERVER) && + $_SERVER['HTTP_REFERER'] != $CFG->wwwroot && + $_SERVER['HTTP_REFERER'] != $CFG->wwwroot.'/' && + $_SERVER['HTTP_REFERER'] != $CFG->httpswwwroot.'/login/' && + $_SERVER['HTTP_REFERER'] != $CFG->httpswwwroot.'/login/index.php') + ? $_SERVER['HTTP_REFERER'] : NULL; + } - if ($_SERVER['REQUEST_METHOD'] === 'GET' // Only on initial GET - // of loginpage - &&!empty($this->config->ntlmsso_enabled)// SSO enabled - && !empty($this->config->ntlmsso_subnet)// have a subnet to test for - && empty($_GET['authldap_skipntlmsso']) // haven't failed it yet - && (isguestuser() || !isloggedin()) // guestuser or not-logged-in users - && address_in_subnet($_SERVER['REMOTE_ADDR'],$this->config->ntlmsso_subnet)) { - redirect("{$CFG->wwwroot}/auth/ldap/ntlmsso_attempt.php"); + // Now start the whole NTLM machinery. + redirect($CFG->wwwroot.'/auth/ldap/ntlmsso_attempt.php'); + } + + // No NTLM SSO, Use the normal login page instead. + + // If $SESSION->wantsurl is empty and we have a 'Referer:' header, the login + // page insists on redirecting us to that page after user validation. If + // we clicked on the redirect link at the ntlmsso_finish.php page instead + // of waiting for the redirection to happen, then we have a 'Referer:' header + // we don't want to use at all. As we can't get rid of it, just point + // $SESSION->wantsurl to $CFG->wwwroot (after all, we came from there). + if (empty($SESSION->wantsurl) + && (get_referer() == $CFG->httpswwwroot.'/auth/ldap/ntlmsso_finish.php')) { + + $SESSION->wantsurl = $CFG->wwwroot; } } @@ -1801,7 +1830,14 @@ class auth_plugin_ldap extends auth_plugin_base { */ function ntlmsso_magic($sesskey) { if (isset($_SERVER['REMOTE_USER']) && !empty($_SERVER['REMOTE_USER'])) { - $username = $_SERVER['REMOTE_USER']; + + // HTTP __headers__ seem to be sent in ISO-8859-1 encoding + // (according to my reading of RFC-1945, RFC-2616 and RFC-2617 and + // my local tests), so we need to convert the REMOTE_USER value + // (i.e., what we got from the HTTP WWW-Authenticate header) into UTF-8 + $textlib = textlib_get_instance(); + $username = $textlib->convert($_SERVER['REMOTE_USER'], 'iso-8859-1', 'utf-8'); + $username = substr(strrchr($username, '\\'), 1); //strip domain info $username = moodle_strtolower($username); //compatibility hack set_cache_flag('auth/ldap/ntlmsess', $sesskey, $username, AUTH_NTLMTIMEOUT); diff --git a/auth/ldap/ntlmsso_attempt.php b/auth/ldap/ntlmsso_attempt.php index 8f2325cf19..fac2bce027 100644 --- a/auth/ldap/ntlmsso_attempt.php +++ b/auth/ldap/ntlmsso_attempt.php @@ -22,7 +22,15 @@ if (empty($authplugin->config->ntlmsso_enabled)) { $sesskey = sesskey(); -//print_header("$site->fullname: $loginsite", $site->fullname, $loginsite, $focus, '', true); +// Display the page header. This makes redirect respect the timeout we specify +// here (and not add 3 more secs) which in turn prevents a bug in both IE 6.x +// and FF 3.x (Windows version at least) where javascript timers fire up even +// when we've already left the page that set the timer. +$loginsite = get_string("loginsite"); +$navlinks = array(array('name' => $loginsite, 'link' => null, 'type' => 'misc')); +$navigation = build_navigation($navlinks); +print_header("$site->fullname: $loginsite", $site->fullname, $navigation, '', '', true); + $msg = '

'.get_string('ntlmsso_attempting','auth').'

' . 'wwwroot . '/login/index.php?authldap_skipntlmsso=1', + // Display the page header. This makes redirect respect the timeout we specify + // here (and not add 3 more secs). + $loginsite = get_string("loginsite"); + $navlinks = array(array('name' => $loginsite, 'link' => null, 'type' => 'misc')); + $navigation = build_navigation($navlinks); + print_header("$site->fullname: $loginsite", $site->fullname, $navigation, '', '', true); + redirect($CFG->httpswwwroot . '/login/index.php?authldap_skipntlmsso=1', get_string('ntlmsso_failed','auth'), 3); } ?> -- 2.39.5