From 43ddb14693e4a4830f471dd7c90f6257d95b7b29 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 27 May 2024 15:37:55 +0200 Subject: Add support for client login via QRCode --- shib/api.php | 1 + shib/client_auth.php | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 shib/client_auth.php (limited to 'shib') diff --git a/shib/api.php b/shib/api.php index eec1e3d..a05c301 100644 --- a/shib/api.php +++ b/shib/api.php @@ -19,6 +19,7 @@ spl_autoload_register(function ($class) require_once $file; }); +// DMSD login via web $response = ShibAuth::login(); Header('Content-Type: text/plain; charset=utf-8'); diff --git a/shib/client_auth.php b/shib/client_auth.php new file mode 100644 index 0000000..0af34de --- /dev/null +++ b/shib/client_auth.php @@ -0,0 +1,142 @@ +.inc.php +spl_autoload_register(function ($class) { + $file = 'inc/' . preg_replace('/[^a-z0-9]/', '', mb_strtolower($class)) . '.inc.php'; + if (!file_exists($file)) + return; + require_once $file; +}); + +#[NoReturn] +function error(string $msg): void +{ + die('
' . htmlspecialchars($msg) . '
'); +} + + + +Header('X-Frame-Options: DENY'); +Header("Content-Security-Policy: frame-ancestors 'none';"); +Header('Content-Type: text/html; charset=utf-8'); + +$token = Request::get('token'); +$qrtoken = !empty(Request::get('qr')); +if (strlen($token) <= 8) { + error('Unknown request'); +} + +// Got a token + +$user = ''; +// Get username from eppn is preferred +if (isset($_SERVER[CONFIG_EPPN])) { + $user = preg_replace('/[^a-z0-9_@\-.]/', '', strtolower($_SERVER[CONFIG_EPPN])); + if (!empty($user) && is_numeric($user[0])) { + $user = 'x' . $user; // First character must not be a digit... + } +} +if (empty($user)) { + // No user - generate random username from persistent-id + $user = 'x' . substr(md5($_SERVER['persistent-id']), 0, 6); +} +if (isset($_SERVER[CONFIG_SCOPED_AFFILIATION]) && !str_contains($user, '@') && preg_match('/@[^@;\s]+/', $_SERVER[CONFIG_SCOPED_AFFILIATION], $out)) { + // We do not have an affiliation in the form of @something.com - try to extract from scoped affiliation + $user .= $out[0]; +} +if (!str_contains($user, '@')) { + // *shrug* + $user .= '@unknown'; +} +if (strlen($user) > 31) { + $user = substr($user, 0, 31); +} +/* +Database::exec("CREATE TABLE IF NOT EXISTS client_token ( + username varchar(128) not null, + token char(32) not null, + dateline int(10) unsigned not null, + KEY (username), + KEY (token), + KEY (dateline) +) DEFAULT CHARSET=ascii COLLATE=ascii_general_ci"); + */ +// Prevent too many attempts (max 20 in 5 mins) +Database::exec("DELETE FROM client_token WHERE dateline < UNIX_TIMESTAMP() - 300"); +$num = Database::queryFirst("SELECT Count(*) AS num FROM client_token WHERE username = :user", ['user' => $user]); +if ($num['num'] > 200) { + error('DoS detected'); +} + +$token2 = substr(md5(mt_rand() . ',' . microtime(true) . ',' . posix_getpid() . ',' + . $_SERVER['REMOTE_ADDR'] . $_SERVER['REMOTE_PORT']), 0, 10); + +// For edit mode via CoW +$dmsd = null; +if (Util::getRole() === 'TUTOR') { + $shibSess = ShibAuth::login(null, 300); + if (!empty($shibSess['token'])) { + $dmsd = $shibSess['token']; + } +} + +// See if valid QR code request +if ($qrtoken) { + $f = Database::queryFirst("SELECT username FROM client_token WHERE qrtoken = :token LIMIT 1", ['token' => $token]); + if ($f === false) { + error('Unknown QR code login token'); + } + if ($f['username'] !== '') { + error('Token already used'); + } + $num = Database::exec("UPDATE client_token SET username = :user, token = :pass, dmsdsession = :dmsd + WHERE username = '' AND qrtoken = :token", + ['user' => $user, 'pass' => $token . $token2, 'token' => $token, 'dmsd' => $dmsd]); + if ($num !== 1) { + error('Token already used'); + } + error('Login erfolgreich. Sie können diese Seite jetzt schließen.'); +} + +// Non-QRCode +Database::exec("INSERT INTO client_token (username, token, dmsdsession, dateline) + VALUES (:user, :pass, :dmsd, UNIX_TIMESTAMP())", + ['user' => $user, 'pass' => $token . $token2, 'dmsd' => $dmsd]); +$hash = md5($token); + +if (!empty($dmsd)) { + $dmsd = "
$dmsd
"; +} + +echo << + + +
+
$user
+
$token2
+
$hash
+ $dmsd +BLUBB; +// For debugging +/* +foreach ($_SERVER as $k => $v) { + if (preg_match('/[a-z]/', $k)) { + echo '
' . htmlspecialchars($v) . '
'; + } +} + */ +echo '
Please wait...'; +exit; -- cgit v1.2.3-55-g7522