PHP Classes

File: server.php

Recommend this page to a friend!
  Classes of Rodrigo Faustino   Digital   server.php   Download  
File: server.php
Role: Example script
Content type: text/plain
Description: Example script
Class: Digital
Authenticate users' fingerprints using WebAuthn
Author: By
Last change:
Date: 15 days ago
Size: 16,676 bytes
 

Contents

Class file image Download
<?php // ini_set('display_errors', 1); // ini_set('display_startup_errors', 1); // error_reporting(E_ALL); /* * Copyright (C) 2022 Lukas Buchs * license https://github.com/lbuchs/WebAuthn/blob/master/LICENSE MIT * * Server test script for WebAuthn library. Saves new registrations in session. * * JAVASCRIPT | SERVER * ------------------------------------------------------------ * * REGISTRATION * * window.fetch -----------------> getCreateArgs * | * navigator.credentials.create <-------------' * | * '-------------------------> processCreate * | * alert ok or fail <----------------' * * ------------------------------------------------------------ * * VALIDATION * * window.fetch ------------------> getGetArgs * | * navigator.credentials.get <----------------' * | * '-------------------------> processGet * | * alert ok or fail <----------------' * * ------------------------------------------------------------ */ require_once 'backend/config/Database.php'; require_once 'backend/controller/UsuarioController.php'; require_once 'backend/model/Usuario.php'; require_once 'src/WebAuthn.php'; header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Headers: *"); header("Content-Type: application/json; charset=UTF-8"); $database = new Database(); $db = new Database(); $usuario = new Usuario(); $controller = new UsuarioController($db,$usuario); try { session_start(); // read get argument and post body $fn = filter_input(INPUT_GET, 'fn'); $requireResidentKey = !!filter_input(INPUT_GET, 'requireResidentKey'); $userVerification = filter_input(INPUT_GET, 'userVerification', FILTER_SANITIZE_SPECIAL_CHARS); $userId = filter_input(INPUT_GET, 'userId', FILTER_SANITIZE_SPECIAL_CHARS); $userName = filter_input(INPUT_GET, 'userName', FILTER_SANITIZE_EMAIL); $userDisplayName = filter_input(INPUT_GET, 'userDisplayName', FILTER_SANITIZE_SPECIAL_CHARS); //$userId = preg_replace('/[^0-9a-f]/i', '', $userId); //$userName = preg_replace('/[^0-9a-z]/i', '', $userName); //$userDisplayName = preg_replace('/[^0-9a-z öüäéèàÖÜÄÉÈÀÂÊÎÔÛâêîôû]/i', '', $userDisplayName); $post = trim(file_get_contents('php://input')); if ($post) { $post = json_decode($post, null, 512, JSON_THROW_ON_ERROR); } if ($fn !== 'getStoredDataHtml') { // Formats $formats = []; if (filter_input(INPUT_GET, 'fmt_android-key')) { $formats[] = 'android-key'; } if (filter_input(INPUT_GET, 'fmt_android-safetynet')) { $formats[] = 'android-safetynet'; } if (filter_input(INPUT_GET, 'fmt_apple')) { $formats[] = 'apple'; } if (filter_input(INPUT_GET, 'fmt_fido-u2f')) { $formats[] = 'fido-u2f'; } if (filter_input(INPUT_GET, 'fmt_none')) { $formats[] = 'none'; } if (filter_input(INPUT_GET, 'fmt_packed')) { $formats[] = 'packed'; } if (filter_input(INPUT_GET, 'fmt_tpm')) { $formats[] = 'tpm'; } $rpId = 'localhost'; if (filter_input(INPUT_GET, 'rpId')) { $rpId = filter_input(INPUT_GET, 'rpId', FILTER_VALIDATE_DOMAIN); if ($rpId === false) { throw new Exception('invalid relying party ID'); } } // types selected on front end $typeUsb = !!filter_input(INPUT_GET, 'type_usb'); $typeNfc = !!filter_input(INPUT_GET, 'type_nfc'); $typeBle = !!filter_input(INPUT_GET, 'type_ble'); $typeInt = !!filter_input(INPUT_GET, 'type_int'); $typeHyb = !!filter_input(INPUT_GET, 'type_hybrid'); // cross-platform: true, if type internal is not allowed // false, if only internal is allowed // null, if internal and cross-platform is allowed $crossPlatformAttachment = null; if (($typeUsb || $typeNfc || $typeBle || $typeHyb) && !$typeInt) { $crossPlatformAttachment = true; } else if (!$typeUsb && !$typeNfc && !$typeBle && !$typeHyb && $typeInt) { $crossPlatformAttachment = false; } // new Instance of the server library. // make sure that $rpId is the domain name. $WebAuthn = new lbuchs\WebAuthn\WebAuthn('WebAuthn Library', $rpId, $formats); // add root certificates to validate new registrations if (filter_input(INPUT_GET, 'solo')) { $WebAuthn->addRootCertificates('rootCertificates/solo.pem'); } if (filter_input(INPUT_GET, 'apple')) { $WebAuthn->addRootCertificates('rootCertificates/apple.pem'); } if (filter_input(INPUT_GET, 'yubico')) { $WebAuthn->addRootCertificates('rootCertificates/yubico.pem'); } if (filter_input(INPUT_GET, 'hypersecu')) { $WebAuthn->addRootCertificates('rootCertificates/hypersecu.pem'); } if (filter_input(INPUT_GET, 'google')) { $WebAuthn->addRootCertificates('rootCertificates/globalSign.pem'); $WebAuthn->addRootCertificates('rootCertificates/googleHardware.pem'); } if (filter_input(INPUT_GET, 'microsoft')) { $WebAuthn->addRootCertificates('rootCertificates/microsoftTpmCollection.pem'); } if (filter_input(INPUT_GET, 'mds')) { $WebAuthn->addRootCertificates('rootCertificates/mds'); } } // ------------------------------------ // request for create arguments // ------------------------------------ if ($fn === 'getCreateArgs') { $createArgs = $WebAuthn->getCreateArgs(\hex2bin($userId), $userName, $userDisplayName, 20, $requireResidentKey, $userVerification, $crossPlatformAttachment); header('Content-Type: application/json'); print(json_encode($createArgs)); // save challange to session. you have to deliver it to processGet later. $_SESSION['desafio'] = $WebAuthn->getChallenge(); // ------------------------------------ // request for get arguments // ------------------------------------ } else if ($fn === 'getGetArgs') { $ids = []; // if ($requireResidentKey) { // if (!isset($_SESSION['registrations']) || !is_array($_SESSION['registrations']) || count($_SESSION['registrations']) === 0) { // throw new Exception('we do not have any registrations in session to check the registration'); // } // } else { //$credentials = $database->read('users', ['userId' => hex2bin($userId)]); $credentials = $controller->verificarLogin(hex2bin($userId)); foreach ($credentials as $credential) { if ($credential['userId'] === hex2bin($userId)) { $ids[] =base64_decode($credential['credentialId']); } } // if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) { // foreach ($_SESSION['registrations'] as $reg) { // if ($reg->userId === $userId) { // $ids[] = $reg->credentialId; // } // } // } if (count($ids) === 0) { // throw new Exception('no registrations in session for userId ' . $userId); throw new Exception('Não há registro na base '); } // } $getArgs = $WebAuthn->getGetArgs($ids, 20, $typeUsb, $typeNfc, $typeBle, $typeHyb, $typeInt, $userVerification); header('Content-Type: application/json'); print(json_encode($getArgs)); // save challange to session. you have to deliver it to processGet later. $_SESSION['desafio'] = $WebAuthn->getChallenge(); // ------------------------------------ // process create // ------------------------------------ } else if ($fn === 'processCreate') { $clientDataJSON = base64_decode($post->clientDataJSON); $attestationObject = base64_decode($post->attestationObject); $challenge = $_SESSION['desafio']; // processCreate returns data to be stored for future logins. // in this example we store it in the php session. // Normaly you have to store the data in a database connected // with the user name. $data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $challenge, $userVerification === 'required', true, false); // add user infos $data->userId = $userId; $data->userName = $userName; $data->userDisplayName = $userDisplayName; // Dados para inserir no banco de dados $serializedChallenge = serialize($_SESSION['desafio']); $dataDb = [ 'rpId' => $data->rpId, 'attestationFormat' => $data->attestationFormat, 'credentialId' => base64_encode($data->credentialId), 'credentialPublicKey' => base64_encode($data->credentialPublicKey), 'certificateChain' => base64_encode($data->certificateChain), 'certificate' => $data->certificate, 'certificateIssuer' => $data->certificateIssuer, 'signatureCounter' => $data->signatureCounter, 'AAGUID' => base64_encode($data->AAGUID), 'rootValid' => base64_encode($data->rootValid), 'userPresent' => $data->userPresent, 'userVerified' => $data->userVerified, 'userId' => hex2bin($data->userId), 'userName' => $data->userName, 'userDisplayName' => $data->userDisplayName, 'challenge'=>$serializedChallenge ]; // Insere os dados no banco de dados $response = $controller->cadastrar($dataDb); //$database->create('users', $dataDb); // if (!isset($_SESSION['registrations']) || !array_key_exists('registrations', $_SESSION) || !is_array($_SESSION['registrations'])) { // $_SESSION['registrations'] = []; // } // $_SESSION['registrations'][] = $data; $msg = 'Registrado com sucesso.'; // if ($data->rootValid === false) { // $msg = 'registration ok, but certificate does not match any of the selected root ca.'; // } $return = new stdClass(); $return->success = true; $return->msg = $msg; header('Content-Type: application/json'); print(json_encode($return)); // ------------------------------------ // proccess get // ------------------------------------ } else if ($fn === 'processGet') { $userId = base64_decode($post->userHandle); $credentials = $controller->verificarLogin($userId); $challengedb=$_SESSION['desafio']; $clientDataJSON = base64_decode($post->clientDataJSON); $authenticatorData = base64_decode($post->authenticatorData); $signature = base64_decode($post->signature); $userHandle = base64_decode($post->userHandle); $id = base64_decode($post->id); $credentialPublicKey = null; foreach ($credentials as $credential) { $credentialId = base64_decode($credential['credentialId']); if ($credentialId === $id) { $credentialPublicKey = base64_decode($credential['credentialPublicKey']); 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 !== $userId) { throw new \Exception('userId doesnt match (is ' . bin2hex($userHandle) . ' but expect ' . $userId . ')'); } // process the get request. throws WebAuthnException if it fails $resultado=$WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $credentialPublicKey, $challengedb, null, $userVerification === 'required'); $return = new stdClass(); $return->success = true; header('Content-Type: application/json'); print(json_encode($return)); if($resultado){ $credentials = $controller->verificarLogin($userId); foreach ($credentials as $credential) { $_SESSION['userName'] = $credential["userName"]; $_SESSION['userDisplayName'] = $credential["userDisplayName"]; } //header("Location: minhaarea.php"); //exit(); } // ------------------------------------ // proccess clear registrations // ------------------------------------ } else if ($fn === 'clearRegistrations') { $_SESSION['registrations'] = null; $_SESSION['challenge'] = null; $return = new stdClass(); $return->success = true; $return->msg = 'all registrations deleted'; header('Content-Type: application/json'); print(json_encode($return)); // ------------------------------------ // display stored data as HTML // ------------------------------------ } // else if ($fn === 'getStoredDataHtml') { // $html = '<!DOCTYPE html>' . "\n"; // $html .= '<html><head><style>tr:nth-child(even){background-color: #f2f2f2;}</style></head>'; // $html .= '<body style="font-family:sans-serif">'; // if (isset($_SESSION['registrations']) && is_array($_SESSION['registrations'])) { // $html .= '<p>There are ' . count($_SESSION['registrations']) . ' registrations in this session:</p>'; // foreach ($_SESSION['registrations'] as $reg) { // $html .= '<table style="border:1px solid black;margin:10px 0;">'; // foreach ($reg as $key => $value) { // if (is_bool($value)) { // $value = $value ? 'yes' : 'no'; // } else if (is_null($value)) { // $value = 'null'; // } else if (is_object($value)) { // $value = chunk_split(strval($value), 64); // } else if (is_string($value) && strlen($value) > 0 && htmlspecialchars($value, ENT_QUOTES) === '') { // $value = chunk_split(bin2hex($value), 64); // } // $html .= '<tr><td>' . htmlspecialchars($key) . '</td><td style="font-family:monospace;">' . nl2br(htmlspecialchars($value)) . '</td>'; // } // $html .= '</table>'; // } // } else { // $html .= '<p>There are no registrations in this session.</p>'; // } // $html .= '</body></html>'; // header('Content-Type: text/html'); // print $html; // // ------------------------------------ // // get root certs from FIDO Alliance Metadata Service // // ------------------------------------ // } else if ($fn === 'queryFidoMetaDataService') { // $mdsFolder = 'rootCertificates/mds'; // $success = false; // $msg = null; // // fetch only 1x / 24h // $lastFetch = \is_file($mdsFolder . '/lastMdsFetch.txt') ? \strtotime(\file_get_contents($mdsFolder . '/lastMdsFetch.txt')) : 0; // if ($lastFetch + (3600*48) < \time()) { // $cnt = $WebAuthn->queryFidoMetaDataService($mdsFolder); // $success = true; // \file_put_contents($mdsFolder . '/lastMdsFetch.txt', date('r')); // $msg = 'successfully queried FIDO Alliance Metadata Service - ' . $cnt . ' certificates downloaded.'; // } else { // $msg = 'Fail: last fetch was at ' . date('r', $lastFetch) . ' - fetch only 1x every 48h'; // } // $return = new stdClass(); // $return->success = $success; // $return->msg = $msg; // header('Content-Type: application/json'); // print(json_encode($return)); // } } catch (Throwable $ex) { $return = new stdClass(); $return->success = false; $return->msg = $ex->getMessage(); header('Content-Type: application/json'); print(json_encode($return)); }