Permalink
Browse files

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
  • Loading branch information...
1 parent 1db15f4 commit f8102d906eab0829b456c9c0fe72f57f127c87ca iarenaza committed Feb 14, 2009
Showing with 64 additions and 14 deletions.
  1. +46 −10 auth/ldap/auth.php
  2. +10 −2 auth/ldap/ntlmsso_attempt.php
  3. +8 −2 auth/ldap/ntlmsso_finish.php
View
@@ -1816,16 +1816,45 @@ function change_password_url() {
*
*/
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;
}
}
@@ -1848,7 +1877,14 @@ function loginpage_hook() {
*/
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);
@@ -22,7 +22,15 @@
$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 = '<p>'.get_string('ntlmsso_attempting','auth').'</p>'
. '<img width="1", height="1" '
. ' src="' . $CFG->wwwroot . '/auth/ldap/ntlmsso_magic.php?sesskey='
@@ -31,4 +39,4 @@
-?>
+?>
@@ -24,7 +24,13 @@
// so we only worry about failure.
if (!$authplugin->ntlmsso_finish()) {
// Redirect to login, saying "don't try again!"
- redirect($CFG->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);
}
-?>
+?>

0 comments on commit f8102d9

Please sign in to comment.