self::$user['organization'])); self::$organization = $org !== false ? $org : null; } return self::$organization; } public static function getShibId() { if (empty(self::$user['shibid'])) return false; return self::$user['shibid']; } public static function load(): bool { //file_put_contents('/tmp/test-' . time(), print_r($_SERVER, true)); if (self::isLoggedIn()) return true; $hasSession = Session::load(); if (empty($_SERVER['persistent-id'])) { if (Session::getUid() === false) { if (!empty($_SERVER['Shib-Session-ID'])) { Message::addError('Sie haben sich erfolgreich mittels {{0}} authentifiziert,' . ' aber der IdP Ihrer Einrichtung scheint die benötigten Metadaten nicht' . ' an den {{1}}-SP zu übermitteln. Bitte wenden Sie sich an den Support.', CONFIG_IDM, CONFIG_SUITE); } Session::delete(); file_put_contents('/tmp/shib-load-' . time() . '-' . $_SERVER['REMOTE_ADDR'] . '.txt', print_r($_SERVER, true)); return false; } // Try user from local DB $usr = Database::queryFirst('SELECT userid, shibid, organizationid AS organization, firstname, lastname, email FROM user WHERE userid = :uid LIMIT 1', ['uid' => Session::getUid()]); self::$user = $usr !== false ? $usr : null; self::$isInDb = self::$user !== null; if (!self::$isInDb) { Session::delete(); } return self::$isInDb; } // Try bwIDM etc. if (!$hasSession) { // Make sure cookies are enabled if (!empty($_SERVER['Shib-Session-ID'])) { if (isset($_GET['force-cookie'])) die('Bitte aktivieren Sie Cookies und Javascript!'); } Session::create(); Session::set('token', md5(mt_rand() . $_SERVER['REMOTE_ADDR'] . microtime(true) . $_SERVER['persistent-id'] . mt_rand())); Session::save(); if (!empty($_SERVER['Shib-Session-ID'])) Util::redirect('?do=Main&force-cookie=true.dat'); } self::$isShib = true; if (!isset($_SERVER[CONFIG_SURNAME])) $_SERVER[CONFIG_SURNAME] = ''; if (!isset($_SERVER['givenName'])) $_SERVER['givenName'] = ''; if (!isset($_SERVER['mail'])) $_SERVER['mail'] = ''; $shibId = []; if (strpos($_SERVER['persistent-id'], ';') !== false) { foreach (explode(';', $_SERVER['persistent-id']) as $s) { $shibId[] = md5($s); } } $shibId[] = md5($_SERVER['persistent-id']); self::$user = array( 'userid' => NULL, 'shibid' => $shibId[0], 'firstname' => $_SERVER['givenName'], 'lastname' => $_SERVER[CONFIG_SURNAME], 'email' => $_SERVER['mail'], ); // Figure out whether the user should be considered a tutor self::$user['role'] = Util::getRole(); // Try to figure out organization if (isset($_SERVER[CONFIG_EPPN]) && preg_match('/@([0-9a-zA-Z\-._]+)$/', $_SERVER[CONFIG_EPPN], $out)) { self::$user['organization'] = $out[1]; } if (!isset(self::$user['organization']) && isset($_SERVER[CONFIG_SCOPED_AFFILIATION]) && preg_match('/@([0-9a-zA-Z\-._]+)(;|$)/', $_SERVER[CONFIG_SCOPED_AFFILIATION], $out)) { self::$user['organization'] = $out[1]; } // Get matching db entry if any $user = Database::queryFirst('SELECT userid, firstname, lastname, email, fixedname FROM user WHERE shibid IN (:shibid) LIMIT 1', ['shibid' => $shibId]); if ($user === false) { // No match in database, user is not signed up return true; } self::$user['userid'] = $user['userid']; if (Session::getUid() === false) { Session::setUid($user['userid']); Session::save(); } // Already signed up, see if we can fetch missing fields from DB self::$isInDb = true; self::$isAnonymous = (empty($user['firstname']) && empty($user['lastname'])); foreach (array('firstname', 'lastname', 'email') as $key) { if (empty(self::$user[$key])) self::$user[$key] = $user[$key]; } return true; } public static function deploy(bool $anonymous, ?string $existingLogin = null): bool { if (empty(self::$user['shibid'])) Util::traceError('NO SHIBID'); if (self::getOrganizationId() === null) { Message::addError('Your home organization ID {{0}} is not known to this server', self::getRemoteOrganizationId()); Util::redirect('?do=Main'); } // Merging with test-account: if (!empty($existingLogin)) { if ($anonymous) { $ret = Database::exec("UPDATE user SET shibid = :shibid, firstname = '', lastname = '', email = '', password = '' " . " WHERE userid = :userid LIMIT 1", array( 'shibid' => self::$user['shibid'], 'userid' => $existingLogin )); } else { $ret = Database::exec("UPDATE user SET shibid = :shibid, password = '', firstname = :firstname, lastname = :lastname, email = :email " . " WHERE userid = :userid LIMIT 1", array( 'shibid' => self::$user['shibid'], 'userid' => $existingLogin, 'firstname' => self::$user['firstname'], 'lastname' => self::$user['lastname'], 'email' => self::$user['email'] )); } return $ret > 0; } // New account if ($anonymous) { Database::exec("INSERT INTO user (shibid, userid, organizationid, firstname, lastname, email) " . " VALUES (:shibid, :shibid, :org, '', '', '') " . " ON DUPLICATE KEY UPDATE firstname = '', lastname = '', email = '', password = ''", array( 'shibid' => self::$user['shibid'], 'org' => self::getOrganizationId() )); } else { Database::exec("INSERT INTO user (shibid, userid, organizationid, firstname, lastname, email) " . " VALUES (:shibid, :shibid, :org, :firstname, :lastname, :email) " . " ON DUPLICATE KEY UPDATE firstname = VALUES(firstname), lastname = VALUES(lastname), email = VALUES(email), password = ''", array( 'shibid' => self::$user['shibid'], 'firstname' => self::$user['firstname'], 'lastname' => self::$user['lastname'], 'email' => self::$user['email'], 'org' => self::getOrganizationId() )); } return true; } public static function updatePassword(string $pass): bool { if (!self::isLoggedIn() || self::$isShib || !self::$isInDb) return false; $pw = Crypto::hash6($pass); $ret = Database::exec('UPDATE user SET password = :pass WHERE userid = :user LIMIT 1', array( 'pass' => $pw, 'user' => self::getId() )); return $ret == 1; } public static function updateMail(string $mail): bool { if (!self::isLoggedIn() || self::$isShib || !self::$isInDb) return false; $ret = Database::exec('UPDATE user SET email = :mail WHERE userid = :user LIMIT 1', array( 'mail' => $mail, 'user' => self::getId() )); return $ret == 1 || $mail === self::$user['email']; } public static function login(string $user, string $pass): bool { $ret = Database::queryFirst('SELECT userid, password FROM user WHERE userid = :user LIMIT 1', array(':user' => $user)); if ($ret === false) return false; if (!Crypto::verify($pass, $ret['password'])) return false; Session::create(); Session::setUid($ret['userid']); Session::set('token', md5(rand() . time() . mt_rand() . $_SERVER['REMOTE_ADDR'] . rand() . $_SERVER['REMOTE_PORT'] . rand() . $_SERVER['HTTP_USER_AGENT'] . microtime(true))); Session::save(); return true; } public static function logout(): never { foreach ($_COOKIE as $name => $value) { if (substr($name, 0, 5) !== '_shib') continue; @setcookie($name, '', time() - CONFIG_SESSION_TIMEOUT, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true); } Session::delete(); if (self::$isShib) { Header('Location: /Shibboleth.sso/Logout'); } else { Header('Location: ?do=Main'); } exit(0); } public static function delete(): bool { if (!User::isLoggedIn() || !User::isInDatabase()) return true; return Database::exec("DELETE FROM user WHERE userid = :userid LIMIT 1", array('userid' => User::getId()), true) > 0; } }