Added login via WebAuth; testing needed

This commit is contained in:
Pinga 2023-12-12 17:52:24 +02:00
parent 63607618e2
commit 68d54f7592
4 changed files with 255 additions and 4 deletions

View file

@ -15,6 +15,32 @@ use Psr\Http\Message\ServerRequestInterface as Request;
*/
class AuthController extends Controller
{
private $webAuthn;
public function __construct() {
$rpName = 'Namingo';
$rpId = envi('APP_DOMAIN');
$formats = [
'android-key',
'android-safetynet',
'apple',
'fido-u2f',
'none',
'packed',
'tpm'
];
$this->webAuthn = new \lbuchs\WebAuthn\WebAuthn($rpName, $rpId, $formats);
$this->webAuthn->addRootCertificates(envi('APP_ROOT').'/vendor/lbuchs/webauthn/_test/rootCertificates/solo.pem');
$this->webAuthn->addRootCertificates(envi('APP_ROOT').'/vendor/lbuchs/webauthn/_test/rootCertificates/apple.pem');
$this->webAuthn->addRootCertificates(envi('APP_ROOT').'/vendor/lbuchs/webauthn/_test/rootCertificates/yubico.pem');
$this->webAuthn->addRootCertificates(envi('APP_ROOT').'/vendor/lbuchs/webauthn/_test/rootCertificates/hypersecu.pem');
$this->webAuthn->addRootCertificates(envi('APP_ROOT').'/vendor/lbuchs/webauthn/_test/rootCertificates/globalSign.pem');
$this->webAuthn->addRootCertificates(envi('APP_ROOT').'/vendor/lbuchs/webauthn/_test/rootCertificates/googleHardware.pem');
$this->webAuthn->addRootCertificates(envi('APP_ROOT').'/vendor/lbuchs/webauthn/_test/rootCertificates/microsoftTpmCollection.pem');
$this->webAuthn->addRootCertificates(envi('APP_ROOT').'/vendor/lbuchs/webauthn/_test/rootCertificates/mds');
}
/**
* @param Request $request
* @param Response $response
@ -57,4 +83,102 @@ class AuthController extends Controller
Auth::logout();
redirect()->route('login');
}
public function getLoginChallenge(Request $request, Response $response)
{
global $container;
$ids = [];
$rawData = $request->getBody();
$data = json_decode($rawData, true);
try {
$db = $container->get('db');
$user = $db->selectValue('SELECT id FROM users WHERE email = ?', [$data['email']]);
if ($user) {
// User found, get the user ID
$userId = $user;
$registrations = $db->select('SELECT id FROM users_webauthn WHERE user_id = ?', [$user]);
if ($registrations) {
foreach ($registrations as $reg) {
$ids[] = $reg['credentialId'];
}
}
if (count($ids) === 0) {
$response->getBody()->write(json_encode(['error' => 'no registrations in session for userId ' . $userId]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
} else {
$response->getBody()->write(json_encode(['error' => 'No user found with the provided email.']));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
} catch (PDOException $e) {
$response->getBody()->write(json_encode(['error' => $e->getMessage()]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$getArgs = $this->webAuthn->getGetArgs($ids, 60*4, true, true, true, true, true, 'required');
$response->getBody()->write(json_encode($getArgs));
$challenge = $this->webAuthn->getChallenge();
$_SESSION['challenge_data'] = $challenge->getBinaryString();
return $response->withHeader('Content-Type', 'application/json');
}
public function verifyLogin(Request $request, Response $response)
{
global $container;
$challengeData = $_SESSION['challenge_data'];
$challenge = new \lbuchs\WebAuthn\Binary\ByteBuffer($challengeData);
$credentialPublicKey = null;
$data = json_decode($request->getBody()->getContents(), null, 512, JSON_THROW_ON_ERROR);
try {
// Decode the incoming data
$clientDataJSON = base64_decode($data->clientDataJSON);
$authenticatorData = base64_decode($data->authenticatorData);
$signature = base64_decode($data->signature);
$userHandle = base64_decode($data->userHandle);
$id = base64_decode($data->id);
$db = $container->get('db');
$credential = $db->select('SELECT public_key FROM users_webauthn WHERE user_id = ?', [$id]);
if ($credential) {
foreach ($registrations as $reg) {
$credentialPublicKey = $reg['public_key'];
break;
}
}
if ($credentialPublicKey === null) {
throw new Exception('Public Key for credential ID not found!');
}
// if we have resident key, we have to verify that the userHandle is the provided userId at registration
if ($requireResidentKey && $userHandle !== hex2bin($reg->userId)) {
throw new \Exception('userId doesnt match (is ' . bin2hex($userHandle) . ' but expect ' . $reg->userId . ')');
}
// process the get request. throws WebAuthnException if it fails
$this->webAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $credentialPublicKey, $challenge, null, $userVerification === 'required');
$return = new \stdClass();
$return->success = true;
$return->msg = $msg;
// Send success response
$response->getBody()->write(json_encode($return));
return $response->withHeader('Content-Type', 'application/json');
} catch (\Exception $e) {
$response->getBody()->write(json_encode(['error' => $e->getMessage()]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
}
}