/** * Does the actual authentication of the user and returns an id that will be used * to load the current user (loadUserOnSession) * * @param STRING $name * @param STRING $password * @return STRING id - used for loading the user * * Contributions by Erik Mitchell erikm@logicpd.com */ function authenticateUser($name, $password) { $GLOBALS['log']->debug('authenticating user.'); // JMH // uncomment the line below to test on the server. this is a temporary solution - John H. (task 9069) // $_POST['SAMLResponse'] = "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgRGVzdGluYXRpb249Imh0dHA6Ly9kZXZzdWdhci5ydHAucmFsZWlnaC5pYm0uY29tL3N1Z2FyLXNhbWwvaW5kZXgucGhwP21vZHVsZT1Vc2VycyZhbXA7YWN0aW9uPUF1dGhlbnRpY2F0ZSIgSUQ9IkZJTVJTUF8xZjUxNjc4Ni0wMTM0LTFmMGQtYWRiZS1iZWE4M2JhM2EyNTEiIEluUmVzcG9uc2VUbz0iXzhmMmFmY2UyNTJiNDVhZGVkNWE4IiBJc3N1ZUluc3RhbnQ9IjIwMTEtMTItMDhUMjA6MTU6NTVaIiBWZXJzaW9uPSIyLjAiPg0KICAgIDxzYW1sOklzc3VlciBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI+aHR0cHM6Ly9sb25kby5ydHAucmFsZWlnaC5pYm0uY29tOjk0NDMvc3BzL1NBTUxJZHAvc2FtbDIwPC9zYW1sOklzc3Vlcj4NCiAgICA8c2FtbHA6U3RhdHVzPg0KICAgICAgICA8c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIj48L3NhbWxwOlN0YXR1c0NvZGU+DQogICAgPC9zYW1scDpTdGF0dXM+DQogICAgPHNhbWw6QXNzZXJ0aW9uIElEPSJBc3NlcnRpb24tdXVpZDFmNTE2NzdkLTAxMzQtMWE2NC05MTA4LWJlYTgzYmEzYTI1MSIgSXNzdWVJbnN0YW50PSIyMDExLTEyLTA4VDIwOjE1OjU1WiIgVmVyc2lvbj0iMi4wIj4NCiAgICAgICAgPHNhbWw6SXNzdWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6ZW50aXR5Ij5odHRwczovL2xvbmRvLnJ0cC5yYWxlaWdoLmlibS5jb206OTQ0My9zcHMvU0FNTElkcC9zYW1sMjA8L3NhbWw6SXNzdWVyPg0KICAgICAgICA8ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIiBJZD0idXVpZDFmNTE2NzgxLTAxMzQtMWRmYS04ZDAwLWJlYTgzYmEzYTI1MSI+DQogICAgICAgICAgICA8ZHM6U2lnbmVkSW5mbz4NCiAgICAgICAgICAgICAgICA8ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyI+PC9kczpDYW5vbmljYWxpemF0aW9uTWV0aG9kPg0KICAgICAgICAgICAgICAgIDxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjcnNhLXNoYTEiPjwvZHM6U2lnbmF0dXJlTWV0aG9kPg0KICAgICAgICAgICAgICAgIDxkczpSZWZlcmVuY2UgVVJJPSIjQXNzZXJ0aW9uLXV1aWQxZjUxNjc3ZC0wMTM0LTFhNjQtOTEwOC1iZWE4M2JhM2EyNTEiPg0KICAgICAgICAgICAgICAgICAgICA8ZHM6VHJhbnNmb3Jtcz4NCiAgICAgICAgICAgICAgICAgICAgICAgIDxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSI+PC9kczpUcmFuc2Zvcm0+DQogICAgICAgICAgICAgICAgICAgICAgICA8ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8eGMxNG46SW5jbHVzaXZlTmFtZXNwYWNlcyB4bWxuczp4YzE0bj0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIiBQcmVmaXhMaXN0PSJ4cyBzYW1sIHhzaSI+PC94YzE0bjpJbmNsdXNpdmVOYW1lc3BhY2VzPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC9kczpUcmFuc2Zvcm0+DQogICAgICAgICAgICAgICAgICAgIDwvZHM6VHJhbnNmb3Jtcz4NCiAgICAgICAgICAgICAgICAgICAgPGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIj48L2RzOkRpZ2VzdE1ldGhvZD4NCiAgICAgICAgICAgICAgICAgICAgPGRzOkRpZ2VzdFZhbHVlPkdMV3BGdkYwYkx3UUVMWFpNZ1ozczFKL3pSUT08L2RzOkRpZ2VzdFZhbHVlPg0KICAgICAgICAgICAgICAgIDwvZHM6UmVmZXJlbmNlPg0KICAgICAgICAgICAgPC9kczpTaWduZWRJbmZvPg0KICAgICAgICAgICAgPGRzOlNpZ25hdHVyZVZhbHVlPkRVaEJueU1UUmFYNlUvT2hDZ2lrN08yZ2hDaXl5akNNOWpHTmk5UE1MMXdidWkyMjNyNCtaRW9tOGdodjVpL3pCOU0yVUhCZTNpdVNEYUUyVGxWVm96Y1h3bHJSUUFaTS9lMVZDck9hRFdhWWJURjZKZ05aM1RWekpDVy9helBNa21aenROV2laY2Z4Q3hjODRkYmlCSzlCQzNOdEdVZGlwWlpQb3h4WUlZYz08L2RzOlNpZ25hdHVyZVZhbHVlPg0KICAgICAgICAgICAgPGRzOktleUluZm8+DQogICAgICAgICAgICAgICAgPGRzOlg1MDlEYXRhPg0KICAgICAgICAgICAgICAgICAgICA8ZHM6WDUwOUNlcnRpZmljYXRlPk1JSUMxekNDQWtDZ0F3SUJBZ0lJRWtvd1hvZlF0eWd3RFFZSktvWklodmNOQVFFRkJRQXdnWW94Q3pBSkJnTlZCQVlUQWxWVE1Rd3dDZ1lEVlFRS0V3TkpRazB4RkRBU0JnTlZCQXNUQzJ4dmJtUnZUbTlrWlRBeE1SZ3dGZ1lEVlFRTEV3OXNiMjVrYjA1dlpHVXdNVU5sYkd3eEdUQVhCZ05WQkFzVEVGSnZiM1FnUTJWeWRHbG1hV05oZEdVeElqQWdCZ05WQkFNVEdXeHZibVJ2TG5KMGNDNXlZV3hsYVdkb0xtbGliUzVqYjIwd0hoY05NVEV4TURBMU1UWXpOekF6V2hjTk1USXhNREEwTVRZek56QXpXakJ2TVFzd0NRWURWUVFHRXdKVlV6RU1NQW9HQTFVRUNoTURTVUpOTVJRd0VnWURWUVFMRXd0c2IyNWtiMDV2WkdVd01URVlNQllHQTFVRUN4TVBiRzl1Wkc5T2IyUmxNREZEWld4c01TSXdJQVlEVlFRREV4bHNiMjVrYnk1eWRIQXVjbUZzWldsbmFDNXBZbTB1WTI5dE1JR2ZNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0R05BRENCaVFLQmdRQ1BkcHBnRnRMWXJJdUdwSE1uNXYzZzdRNXRPdHZRZzh4WW9nVjkzdnJBTWhtcUlGWkFqUkFzWXdGc3lyaFQ3UnVxckttaEhtbnEvSUlQcHVWbGhZRjZvZisyTEExZ0VkSGMyb1lBRk5WNUl5cFdRS1JjUWF6RlNHc2FqQktLUExjclNaY20zQVNHYlYySHVNKytNMFZmMWs4Q3hqM1hOb1NIRjJRZnZVUHZmUUlEQVFBQm8yQXdYakJKQmdOVkhSRUVRakJBZ1Q1UWNtOW1hV3hsVlZWSlJEcEJjSEJUY25Zd01TMUNRVk5GTFRJM1ltRmhOMlEzTFRoallUTXROR1F6T1MxaU1qYzNMVEprWm1VNE1tSXpaamxtWXpBUkJnTlZIUTRFQ2dRSVFxUWFNYVlyYmE4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQWxJd0FlZnpnRXRLeXBBazJndkhFQnk1Njc1UGtBcU5MT3ZrN2JDRVRsQnVXdTAya0N2bGtSQ09FdFJCanIrbVBHYkRaaHRTZEt3SkFibDhiSXYvYkgzVnpSVHd3ODdYaUZzVzFPbDViL3o0SVBWcmhDVFFPMWVMQ2w2N3kycHd4SmROYWxOQUFXelpERytRSjNFQlp6K3hxUVdKbktRTkVjQjY3K0xBVXNHRT08L2RzOlg1MDlDZXJ0aWZpY2F0ZT4NCiAgICAgICAgICAgICAgICA8L2RzOlg1MDlEYXRhPg0KICAgICAgICAgICAgPC9kczpLZXlJbmZvPg0KICAgICAgICA8L2RzOlNpZ25hdHVyZT4NCiAgICAgICAgPHNhbWw6U3ViamVjdD4NCiAgICAgICAgICAgIDxzYW1sOk5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OnVuc3BlY2lmaWVkIj5DLUNCVEs4OTc8L3NhbWw6TmFtZUlEPg0KICAgICAgICAgICAgPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbiBNZXRob2Q9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjbTpiZWFyZXIiPg0KICAgICAgICAgICAgICAgIDxzYW1sOlN1YmplY3RDb25maXJtYXRpb25EYXRhIEluUmVzcG9uc2VUbz0iXzhmMmFmY2UyNTJiNDVhZGVkNWE4IiBOb3RPbk9yQWZ0ZXI9IjIwMTEtMTItMDhUMjA6MTY6NTVaIiBSZWNpcGllbnQ9Imh0dHA6Ly9kZXZzdWdhci5ydHAucmFsZWlnaC5pYm0uY29tL3N1Z2FyLXNhbWwvaW5kZXgucGhwP21vZHVsZT1Vc2VycyZhbXA7YWN0aW9uPUF1dGhlbnRpY2F0ZSI+PC9zYW1sOlN1YmplY3RDb25maXJtYXRpb25EYXRhPg0KICAgICAgICAgICAgPC9zYW1sOlN1YmplY3RDb25maXJtYXRpb24+DQogICAgICAgIDwvc2FtbDpTdWJqZWN0Pg0KICAgICAgICA8c2FtbDpDb25kaXRpb25zIE5vdEJlZm9yZT0iMjAxMC0xMi0wOFQyMDoxNDo1NVoiIE5vdE9uT3JBZnRlcj0iMjAxMy0xMi0wOFQyMDoxNjo1NVoiPg0KICAgICAgICAgICAgPHNhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj4NCiAgICAgICAgICAgICAgICA8c2FtbDpBdWRpZW5jZT5waHAtc2FtbDwvc2FtbDpBdWRpZW5jZT4NCiAgICAgICAgICAgIDwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uPg0KICAgICAgICA8L3NhbWw6Q29uZGl0aW9ucz4NCiAgICAgICAgPHNhbWw6QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIyMDExLTEyLTA4VDIwOjE1OjU1WiIgU2Vzc2lvbkluZGV4PSJ1dWlkMWY0ZTU2MzItMDEzNC0xNjRlLTk1MWItYmVhODNiYTNhMjUxIiBTZXNzaW9uTm90T25PckFmdGVyPSIyMDExLTEyLTA4VDIxOjE1OjU1WiI+DQogICAgICAgICAgICA8c2FtbDpBdXRobkNvbnRleHQ+DQogICAgICAgICAgICAgICAgPHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+DQogICAgICAgICAgICA8L3NhbWw6QXV0aG5Db250ZXh0Pg0KICAgICAgICA8L3NhbWw6QXV0aG5TdGF0ZW1lbnQ+DQogICAgICAgIDxzYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD4NCiAgICAgICAgICAgIDxzYW1sOkF0dHJpYnV0ZSBOYW1lPSJETl9WYWx1ZSIgTmFtZUZvcm1hdD0idXJuOmlibTpuYW1lczpJVEZJTTo1LjE6YWNjZXNzbWFuYWdlciI+DQogICAgICAgICAgICAgICAgPHNhbWw6QXR0cmlidXRlVmFsdWUgeHNpOnR5cGU9InhzOnN0cmluZyI+dWlkPUMtQ0JUSzg5NyxjPXVzLG91PWJsdWVwYWdlcyxvPWlibS5jb208L3NhbWw6QXR0cmlidXRlVmFsdWU+DQogICAgICAgICAgICA8L3NhbWw6QXR0cmlidXRlPg0KICAgICAgICA8L3NhbWw6QXR0cmlidXRlU3RhdGVtZW50Pg0KICAgIDwvc2FtbDpBc3NlcnRpb24+DQo8L3NhbWxwOlJlc3BvbnNlPg=="; if (empty($_POST['SAMLResponse'])) { return parent::authenticateUser($name, $password); } $GLOBALS['log']->debug('have saml data.'); // JMH // Look for custom versions of settings.php if it exists require get_custom_file_if_exists('modules/Users/authentication/SAMLAuthenticate/settings.php'); require 'modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml.php'; $samlresponse = new SamlResponse(get_saml_settings(), $_POST['SAMLResponse']); if ($samlresponse->is_valid()) { $GLOBALS['log']->debug('response is valid'); $settings = get_saml_settings(); $customFields = $this->getAdditionalFieldsToSelect($samlresponse, $settings); $GLOBALS['log']->debug('got this many custom fields:' . count($customFields)); $xmlDoc = new DOMDocument(); $xmlDoc->loadXML(base64_decode($_POST['SAMLResponse'])); $xpath = new DOMXpath($xmlDoc); $query = $settings->saml_settings['check']['user_name']; $entries = $xpath->query($query); $nameId = $entries->item(0)->nodeValue; $sql = "SELECT id, status {$customFields} FROM users WHERE " . $settings->id . "='" . $nameId . "' AND deleted = 0"; $dbresult = $GLOBALS['db']->query("SELECT id, status {$customFields} FROM users WHERE " . $settings->id . "='" . $nameId . "' AND deleted = 0"); $GLOBALS['log']->debug("sql: {$sql}"); // JMH $GLOBALS['log']->debug('queried the db'); // JMH //user already exists use this one if ($row = $GLOBALS['db']->fetchByAssoc($dbresult)) { $GLOBALS['log']->debug('have db results'); // JMH if ($row['status'] != 'Inactive') { $GLOBALS['log']->debug('have current user'); // JMH $this->updateCustomFields($row, $_POST['SAMLResponse'], $settings); return $row['id']; } else { $GLOBALS['log']->debug('have inactive user'); // JMH return ''; } } else { if (isset($settings->customCreateFunction)) { call_user_func($settings->customCreateFunction, $this, $samlresponse->get_nameid(), $xpath, $settings); } else { return $this->createUser($samlresponse->get_nameid(), $xpath, $settings); } } // comment out the following two lines for testing - John H. (task 9069) } return ''; }
/** * Does the actual authentication of the user and returns an id that will be used * to load the current user (loadUserOnSession) * * @param STRING $name * @param STRING $password * @return STRING id - used for loading the user * * Contributions by Erik Mitchell erikm@logicpd.com */ function authenticateUser($name, $password) { if (empty($_POST['SAMLResponse'])) { return parent::authenticateUser($name, $password); } require 'modules/Users/authentication/SAMLAuthenticate/settings.php'; require 'modules/Users/authentication/SAMLAuthenticate/lib/onelogin/saml.php'; $samlresponse = new SamlResponse(get_saml_settings(), $_POST['SAMLResponse']); if ($samlresponse->is_valid()) { $dbresult = $GLOBALS['db']->query("SELECT id, status FROM users WHERE user_name='" . $samlresponse->get_nameid() . "' AND deleted = 0"); //user already exists use this one if ($row = $GLOBALS['db']->fetchByAssoc($dbresult)) { if ($row['status'] != 'Inactive') { return $row['id']; } else { return ''; } } else { return $this->createUser($samlresponse->get_nameid()); } } return ''; }
/** * Checks the session to see if the user is already logged in * * If not logged in, redirects to SAML provider */ public function trustExternal($user, $pass, $sticky = false) { global $USERINFO; global $ID; global $ACT; global $conf; // trust session info, no need to recheck if (isset($_SESSION[DOKU_COOKIE]['auth']) && $_SESSION[DOKU_COOKIE]['auth']['buid'] == auth_browseruid() && isset($_SESSION[DOKU_COOKIE]['auth']['user'])) { $_SERVER['REMOTE_USER'] = $_SESSION[DOKU_COOKIE]['auth']['user']; $USERINFO = $_SESSION[DOKU_COOKIE]['auth']['info']; return true; } if (!isset($_POST['SAMLResponse']) && ($ACT == 'login' || get_doku_pref('adfs_autologin', 0))) { // Initiate SAML auth request $authrequest = new SamlAuthRequest($this->settings); $url = $authrequest->create(); $_SESSION['adfs_redirect'] = wl($ID, '', true, '&'); // remember current page send_redirect($url); } elseif (isset($_POST['SAMLResponse'])) { // consume SAML response $samlresponse = new SamlResponse($this->settings, $_POST['SAMLResponse']); try { if ($samlresponse->is_valid()) { $_SERVER['REMOTE_USER'] = $samlresponse->get_attribute('login'); $USERINFO['user'] = $_SERVER['REMOTE_USER']; $USERINFO['name'] = $samlresponse->get_attribute('fullname'); $USERINFO['mail'] = $samlresponse->get_attribute('email'); $USERINFO['grps'] = (array) $samlresponse->get_attribute('groups'); $USERINFO['grps'][] = $conf['defaultgroup']; $USERINFO['grps'] = array_map(array($this, 'cleanGroup'), $USERINFO['grps']); $_SESSION[DOKU_COOKIE]['auth']['user'] = $_SERVER['REMOTE_USER']; $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; $_SESSION[DOKU_COOKIE]['auth']['buid'] = auth_browseruid(); # cache login // cache user data $changes = array('name' => $USERINFO['name'], 'mail' => $USERINFO['mail'], 'grps' => $USERINFO['grps']); if ($this->triggerUserMod('modify', array($user, $changes)) === false) { $this->triggerUserMod('create', array($user, "nil", $USERINFO['name'], $USERINFO['mail'], $USERINFO['grps'])); } // successful login if (isset($_SESSION['adfs_redirect'])) { $go = $_SESSION['adfs_redirect']; unset($_SESSION['adfs_redirect']); } else { $go = wl($ID, '', true, '&'); } set_doku_pref('adfs_autologin', 1); send_redirect($go); // decouple the history from POST return true; } else { $this->logOff(); msg('The SAML response signature was invalid.', -1); return false; } } catch (Exception $e) { $this->logOff(); msg('Invalid SAML response: ' . hsc($e->getMessage()), -1); return false; } } // no login happened return false; }
$pluginconfig = get_config('auth/onelogin_saml'); if (!isset($_POST['SAMLResponse']) && !(isset($_GET['normal']) && $_GET['normal'] || isset($SESSION->normal) && $SESSION->normal) && !(isset($_GET['logout']) && $_GET['logout'])) { ## myDebugger("SAML REQUEST"); $onelogin_saml_issuer = "onelogin_saml"; $onelogin_saml_name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"; require_once 'lib/onelogin/saml.php'; $authrequest = new AuthRequest(); $authrequest->user_settings = get_user_settings(); $onelogin_saml_url = $authrequest->create(); redirect($onelogin_saml_url, 0); } elseif (isset($_POST['SAMLResponse']) && $_POST['SAMLResponse'] && !(isset($_GET['normal']) && $_GET['normal']) || isset($SESSION->normal) && $SESSION->normal && !(isset($_GET['logout']) && $_GET['logout'])) { ## myDebugger("SAML RESPONSE"); require_once 'lib/onelogin/saml.php'; $samlresponse = new SamlResponse($_POST['SAMLResponse']); $samlresponse->user_settings = get_user_settings(); if (!$samlresponse->is_valid()) { print_error("An invalid SAML response was received from the Identity Provider. Contact the admin."); } //onelogin_saml_auth($samlresponse); $username = $onelogin_saml_nameId = $samlresponse->get_nameid(); // make variables accessible to saml->get_userinfo; Information will be requested from authenticate_user_login -> create_user_record / update_user_record $GLOBALS['onelogin_saml_login_attributes'] = $saml_attributes = $samlresponse->get_saml_attributes(); ## myDebugger("<pre>SAML ATTRIBUTES...<br />".print_r($saml_attributes, true)."SAML...<br />".htmlentities(base64_decode($_POST['SAMLResponse']))."</pre>"); $wantsurl = isset($SESSION->wantsurl) ? $SESSION->wantsurl : FALSE; } else { // You shouldn't be able to reach here. print_error("Module Setup Error: Review the OneLogin setup instructions for the SAML authentication module, and be sure to change the following one line of code in Moodle's core in 'login/index.php'.<br /><br /><div style=\"text-align:center;\">CHANGE THE FOLLOWING LINE OF CODE (in 'login/index.php')...</div><br /><font style=\"font-size:18px;\"><strong>if (!empty(\$CFG->alternateloginurl)) {</strong></font><br /><br /><div style=\"text-align:center;\">...to...</div><br /><strong><font style=\"font-size:18px;\">if (!empty(\$CFG->alternateloginurl) && !isset(\$_GET['normal'])) { </font></strong> \r\n"); } ///$wantsurl = isset($SESSION->wantsurl) ? $SESSION->wantsurl : FALSE; ///unset($SESSION->retry); ///unset($SESSION->wantsurl);