summaryrefslogblamecommitdiffstats
path: root/shib/client_auth.php
blob: 0af34de511908bb8cef39d901f8671f8ea3d08b9 (plain) (tree)













































































































































                                                                                                                                                      
<?php

use JetBrains\PhpStorm\NoReturn;

chdir('..');

require_once 'config.php';

/*
Header('Content-Type: text/plain; charset=utf-8');
die( json_encode($_SERVER, JSON_PRETTY_PRINT) );

// */

// Autoload classes from ./inc which adhere to naming scheme <lowercasename>.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('<!doctype html><html lang="en"><body><div id="bwlp-error">' . htmlspecialchars($msg) . '</div></body></html>');
}



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 = "<div id=\"bwlp-cow-token\">$dmsd</div>";
}

echo <<<BLUBB
<!doctype html>
<html lang="en">
<body>
	<div style="display:none">
		<div id="bwlp-username">$user</div>
		<div id="bwlp-password">$token2</div>
		<div id="bwlp-hash">$hash</div>
		$dmsd
BLUBB;
// For debugging
/*
foreach ($_SERVER as $k => $v) {
	if (preg_match('/[a-z]/', $k)) {
		echo '<div id="' . htmlspecialchars($k) . '">' . htmlspecialchars($v) . '</div>';
	}
}
 */
echo '</div>Please wait...</body></html>';
exit;