From decd80163d5ca7a16c64dea972e8953fe41e7383 Mon Sep 17 00:00:00 2001 From: martinlanghoff Date: Wed, 14 Nov 2007 22:08:11 +0000 Subject: [PATCH] MDL-9399 auth/ldap: flesh out ntlmsso_* functions Flesh out the functions that get the job done. These will be triggered by PHP files sitting under auth/ldap/ ... ntlmsso_magic() - here is where the magic happens. Call it serving something harmless, like a space GIF, from a URL that is blessed with Integrated Windows Authentication. If the IWA is successful, it will set a special session cookie in config_plugins table. It won't complete the job because when we are under IWA magic we cannot change (even read!) the session data, as the execution happens under the OS privileges of the actual user acct being logged in (!!!) ntlmsso_finish() - if it finds the session set by ntlmsso_magic() and it hasn't expired, it will finish the job of logging in the user, by calling authenticate_user_login() and exercising the whole auth machinery. user_login() - when called by authenticate_user_login() it will check to see if there's a session setup by ntlmsso_magic() and OK the login without really asking the AD backend to proof a password we don't have anyway. --- auth/ldap/auth.php | 67 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/auth/ldap/auth.php b/auth/ldap/auth.php index 215834c677..e8f42b396b 100644 --- a/auth/ldap/auth.php +++ b/auth/ldap/auth.php @@ -81,6 +81,33 @@ class auth_plugin_ldap extends auth_plugin_base { return false; } + // + // Before we connect to LDAP, check if this is an AD SSO login + // + if (!empty($this->ntlmsso_enabled)) { + $key = $_SERVER['REMOTE_ADDR']; + if ($cookie = get_config('auth/ldap/ntlmsess', $key)) { + // These checks match the work done + if (preg_match('/^(\d+):.{10}:(.+)$/',$cookie,$matches)) { + // $matches[0] is the whole matched string... + $time = $matches[1]; + $sesskey = $matches[2]; + $sessusername = $matches[3]; + if (((int)$time < now() - 6) // timewindow for the process, in secs... + && $sesskey === sesskey() + && $sesskey === $password + && $sessusername === $username) { + return true; + } + } + } + unset($cookie); + unset($key); + unset($time); + unset($sessusername); + } + + $textlib = textlib_get_instance(); $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); $extpassword = $textlib->convert(stripslashes($password), 'utf-8', $this->config->ldapencoding); @@ -1729,26 +1756,56 @@ class auth_plugin_ldap extends auth_plugin_base { * "Integrated Windows Authentication". * * If successful, it will set a special "cookie" (not an HTTP cookie!) - * in config_plugin under the "auth/ldap/ntlmsess" "plugin" and redirect. + * in config_plugin under the "auth/ldap/ntlmsess" "plugin" and return true. * The "cookie" will be picked up by ntlmsso_finish() to complete the * process. * * On failure it will return false for the caller to display an appropriate - * error message. + * error message (probably saying that Integrated Windows Auth isn't enabled!) * * NOTE that this code will execute under the OS user credentials, * so we MUST avoid dealing with files -- such as session files. * */ - function ntlmsso_attempt() { - + function ntlmsso_magic($sesskey) { + if (isset($_SERVER['REMOTE_USER']) && !empty($_SERVER['REMOTE_USER'])) { + $username = $_SERVER['REMOTE_USER']; + $username = substr(strrchr($username, '\\'), 1); //strip domain info + $username = strtolower($username); //compatibility hack + $key = $_SERVER['REMOTE_ADDR']; // add sesskey? + $value = now() . ':' . $sesskey . ':' . $username; + return set_config($key, $value, 'auth/ldap/ntlmsess'); + } + return false; } /** + * Find the session set by ntlmsso_magic(), validate it and + * call authenticate_user_login() to authenticate the user through + * the auth machinery. + * + * It is complemented by a similar check in user_login(). * + * If it succeeds, it never returns. + * */ function ntlmsso_finish() { - + $key = $_SERVER['REMOTE_ADDR']; // add sesskey? + if ($cookie = get_config('auth/ldap/ntlmsess', $key)) { + if (preg_match('/^(\d+):.{10}:(.+)$/',$cookie,$matches)) { + // $matches[0] is the whole matched string... + $time = $matches[1]; + $sesskey = $matches[2]; + $username = $matches[3]; + if (((int)$time < now() - 6) // timewindow for the process, in secs... + && $sesskey === sesskey()) { + // Here we want to trigger the whole authentication machinery + // to make sure no step is bypassed... + authenticate_user_login($username, $sesskey); + } + } + } + return false; } /** -- 2.39.5