Webauthn抽象
This commit is contained in:
parent
f32c2e6344
commit
4c967584ad
@ -32,8 +32,6 @@ use Webauthn\TokenBinding\IgnoreTokenBindingHandler;
|
|||||||
|
|
||||||
class UserWebAuthnController extends BaseController
|
class UserWebAuthnController extends BaseController
|
||||||
{
|
{
|
||||||
private $attestationStatementSupportManager = null;
|
|
||||||
|
|
||||||
public function webauthn_login(Request $request)
|
public function webauthn_login(Request $request)
|
||||||
{
|
{
|
||||||
return view("user.webauthn.login");
|
return view("user.webauthn.login");
|
||||||
@ -68,12 +66,21 @@ class UserWebAuthnController extends BaseController
|
|||||||
public function register_validate(Request $request)
|
public function register_validate(Request $request)
|
||||||
{
|
{
|
||||||
if (!$request->session()->has("webauthn_register_challenge")) {
|
if (!$request->session()->has("webauthn_register_challenge")) {
|
||||||
///
|
return new Response([
|
||||||
|
"success" => false,
|
||||||
|
"code" => 403,
|
||||||
|
"message" => "重放攻击可能?无对应验证请求"
|
||||||
|
], 403);
|
||||||
}
|
}
|
||||||
$publicKeyCredential = $this->get_public_key_credential_loader()->loadArray($request->json()->all());
|
$publicKeyCredential = WebAuthnService::getPublicKeyCredentialLoader()->loadArray($request->json()->all());
|
||||||
$authenticatorAttestationResponse = $publicKeyCredential->getResponse();
|
$authenticatorAttestationResponse = $publicKeyCredential->getResponse();
|
||||||
if (!$authenticatorAttestationResponse instanceof AuthenticatorAttestationResponse) {
|
if (!$authenticatorAttestationResponse instanceof AuthenticatorAttestationResponse) {
|
||||||
//e.g. process here with a redirection to the public key creation page.
|
//e.g. process here with a redirection to the public key creation page.
|
||||||
|
return new Response([
|
||||||
|
"success" => false,
|
||||||
|
"code" => 400,
|
||||||
|
"message" => "接口调用错误?无法验证请求"
|
||||||
|
], 400);
|
||||||
}
|
}
|
||||||
$userEntity = new PublicKeyCredentialUserEntity(
|
$userEntity = new PublicKeyCredentialUserEntity(
|
||||||
$request->user("web")->name,
|
$request->user("web")->name,
|
||||||
@ -82,31 +89,49 @@ class UserWebAuthnController extends BaseController
|
|||||||
);
|
);
|
||||||
$challenge = $request->session()->remove("webauthn_register_challenge");
|
$challenge = $request->session()->remove("webauthn_register_challenge");
|
||||||
$publicKeyCredentialCreationOptions = WebAuthnService::createRequestOptions($userEntity, $challenge);
|
$publicKeyCredentialCreationOptions = WebAuthnService::createRequestOptions($userEntity, $challenge);
|
||||||
$publicKeyCredentialSource = $this->get_authn_attestation_response_validator()->check(
|
try {
|
||||||
$authenticatorAttestationResponse,
|
$publicKeyCredentialSource = WebAuthnService::getAuthenticatorAttestationResponseValidator()->check(
|
||||||
$publicKeyCredentialCreationOptions,
|
$authenticatorAttestationResponse,
|
||||||
ServerRequest::fromGlobals(),
|
$publicKeyCredentialCreationOptions,
|
||||||
["localhost"]
|
ServerRequest::fromGlobals(),
|
||||||
);
|
["localhost"]
|
||||||
$this->get_pub_key_cred_source_repository()->saveCredentialSource($publicKeyCredentialSource);
|
);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return new Response([
|
||||||
|
"success" => false,
|
||||||
|
"code" => 500,
|
||||||
|
"message" => "服务器异常",
|
||||||
|
"exception" => $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
WebAuthnService::getPublicKeyCredentialSourceRepository()->saveCredentialSource($publicKeyCredentialSource);
|
||||||
return $publicKeyCredentialSource;
|
return $publicKeyCredentialSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login_validate(Request $request)
|
public function login_validate(Request $request)
|
||||||
{
|
{
|
||||||
if (!$request->session()->has("webauthn_login_challenge")) {
|
if (!$request->session()->has("webauthn_login_challenge")) {
|
||||||
///
|
return new Response([
|
||||||
|
"success" => false,
|
||||||
|
"code" => 403,
|
||||||
|
"message" => "重放攻击可能?无对应验证请求"
|
||||||
|
], 403);
|
||||||
}
|
}
|
||||||
$publicKeyCredentialRequestOptions = new PublicKeyCredentialRequestOptions(
|
$publicKeyCredentialRequestOptions = new PublicKeyCredentialRequestOptions(
|
||||||
$request->session()->remove("webauthn_login_challenge")
|
$request->session()->remove("webauthn_login_challenge")
|
||||||
);
|
);
|
||||||
$publicKeyCredential = $this->get_public_key_credential_loader()->loadArray($request->json()->all());
|
$publicKeyCredential = WebAuthnService::getPublicKeyCredentialLoader()->loadArray($request->json()->all());
|
||||||
$authenticatorAssertionResponse = $publicKeyCredential->getResponse();
|
$authenticatorAssertionResponse = $publicKeyCredential->getResponse();
|
||||||
if (!$authenticatorAssertionResponse instanceof AuthenticatorAssertionResponse) {
|
if (!$authenticatorAssertionResponse instanceof AuthenticatorAssertionResponse) {
|
||||||
//e.g. process here with a redirection to the public key login/MFA page.
|
//e.g. process here with a redirection to the public key login/MFA page.
|
||||||
|
return new Response([
|
||||||
|
"success" => false,
|
||||||
|
"code" => 400,
|
||||||
|
"message" => "接口调用错误?无法验证请求"
|
||||||
|
], 400);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$publicKeyCredentialSource = $this->get_authn_assertion_response_validator()->check(
|
$publicKeyCredentialSource = WebAuthnService::getAuthenticatorAssertionResponseValidator()->check(
|
||||||
$publicKeyCredential->getRawId(),
|
$publicKeyCredential->getRawId(),
|
||||||
$authenticatorAssertionResponse,
|
$authenticatorAssertionResponse,
|
||||||
$publicKeyCredentialRequestOptions,
|
$publicKeyCredentialRequestOptions,
|
||||||
@ -115,7 +140,12 @@ class UserWebAuthnController extends BaseController
|
|||||||
["localhost"]
|
["localhost"]
|
||||||
);
|
);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return new Response($e->getMessage(), 500);
|
return new Response([
|
||||||
|
"success" => false,
|
||||||
|
"code" => 500,
|
||||||
|
"message" => "服务器异常",
|
||||||
|
"exception" => $e->getMessage()
|
||||||
|
], 500);
|
||||||
}
|
}
|
||||||
Auth::loginUsingId($publicKeyCredentialSource->getUserHandle());
|
Auth::loginUsingId($publicKeyCredentialSource->getUserHandle());
|
||||||
return [
|
return [
|
||||||
@ -125,52 +155,4 @@ class UserWebAuthnController extends BaseController
|
|||||||
"userId" => $publicKeyCredentialSource->getUserHandle()
|
"userId" => $publicKeyCredentialSource->getUserHandle()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function get_authn_attestation_response_validator(): AuthenticatorAttestationResponseValidator
|
|
||||||
{
|
|
||||||
$authenticatorAttestationResponseValidator = new AuthenticatorAttestationResponseValidator(
|
|
||||||
$this->get_attestation_stmt_sup_mgr(),
|
|
||||||
WebAuthnService::getPublicKeyCredentialSourceRepository(),
|
|
||||||
new IgnoreTokenBindingHandler(),
|
|
||||||
new ExtensionOutputCheckerHandler()
|
|
||||||
);
|
|
||||||
return $authenticatorAttestationResponseValidator;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_authn_assertion_response_validator(): AuthenticatorAssertionResponseValidator
|
|
||||||
{
|
|
||||||
$algorithmManager = new Manager();
|
|
||||||
$algorithmManager->add(new ES256());
|
|
||||||
$algorithmManager->add(new RS256());
|
|
||||||
$authenticatorAssertionResponseValidator = new AuthenticatorAssertionResponseValidator(
|
|
||||||
WebAuthnService::getPublicKeyCredentialSourceRepository(),
|
|
||||||
new IgnoreTokenBindingHandler(),
|
|
||||||
new ExtensionOutputCheckerHandler(),
|
|
||||||
$algorithmManager
|
|
||||||
);
|
|
||||||
return $authenticatorAssertionResponseValidator;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_public_key_credential_loader(): PublicKeyCredentialLoader
|
|
||||||
{
|
|
||||||
$publicKeyCredentialLoader = new PublicKeyCredentialLoader(
|
|
||||||
$this->get_attestation_loader()
|
|
||||||
);
|
|
||||||
return $publicKeyCredentialLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_attestation_loader(): AttestationObjectLoader
|
|
||||||
{
|
|
||||||
$attestationObjectLoader = new AttestationObjectLoader($this->get_attestation_stmt_sup_mgr());
|
|
||||||
return $attestationObjectLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_attestation_stmt_sup_mgr()
|
|
||||||
{
|
|
||||||
if ($this->attestationStatementSupportManager === null) {
|
|
||||||
$this->attestationStatementSupportManager = new AttestationStatementSupportManager();
|
|
||||||
$this->attestationStatementSupportManager->add(new NoneAttestationStatementSupport());
|
|
||||||
}
|
|
||||||
return $this->attestationStatementSupportManager;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,20 +3,33 @@
|
|||||||
namespace App\WebAuthn;
|
namespace App\WebAuthn;
|
||||||
|
|
||||||
use App\WebAuthn\Repository\PublicKeyCredentialSourceRepositoryImpl;
|
use App\WebAuthn\Repository\PublicKeyCredentialSourceRepositoryImpl;
|
||||||
|
use Cose\Algorithm\Manager;
|
||||||
|
use Cose\Algorithm\Signature\ECDSA\ES256;
|
||||||
|
use Cose\Algorithm\Signature\RSA\RS256;
|
||||||
use Cose\Algorithms;
|
use Cose\Algorithms;
|
||||||
|
use Webauthn\AttestationStatement\AttestationObjectLoader;
|
||||||
|
use Webauthn\AttestationStatement\AttestationStatementSupportManager;
|
||||||
|
use Webauthn\AttestationStatement\NoneAttestationStatementSupport;
|
||||||
|
use Webauthn\AuthenticationExtensions\ExtensionOutputCheckerHandler;
|
||||||
|
use Webauthn\AuthenticatorAssertionResponseValidator;
|
||||||
|
use Webauthn\AuthenticatorAttestationResponseValidator;
|
||||||
use Webauthn\AuthenticatorSelectionCriteria;
|
use Webauthn\AuthenticatorSelectionCriteria;
|
||||||
use Webauthn\PublicKeyCredentialCreationOptions;
|
use Webauthn\PublicKeyCredentialCreationOptions;
|
||||||
|
use Webauthn\PublicKeyCredentialLoader;
|
||||||
use Webauthn\PublicKeyCredentialParameters;
|
use Webauthn\PublicKeyCredentialParameters;
|
||||||
use Webauthn\PublicKeyCredentialRpEntity;
|
use Webauthn\PublicKeyCredentialRpEntity;
|
||||||
use Webauthn\PublicKeyCredentialSourceRepository;
|
use Webauthn\PublicKeyCredentialSourceRepository;
|
||||||
use Webauthn\PublicKeyCredentialUserEntity;
|
use Webauthn\PublicKeyCredentialUserEntity;
|
||||||
|
use Webauthn\TokenBinding\IgnoreTokenBindingHandler;
|
||||||
|
|
||||||
class WebAuthnService
|
class WebAuthnService
|
||||||
{
|
{
|
||||||
private static $rpName = "开心鄢的录播查询小站";
|
private static $rpName = "开心鄢的录播查询小站";
|
||||||
private static $rpId = "localhost";
|
private static $rpId = "comment.sc.jerryyan.top";
|
||||||
private static $timeout = 45000;
|
private static $timeout = 45000;
|
||||||
private static $publicKeyCredentialSourceRepositoryInstance = null;
|
private static $publicKeyCredentialSourceRepositoryInstance = null;
|
||||||
|
private static $authenticatorAssertionResponseValidator = null;
|
||||||
|
private static $attestationStatementSupportManager = null;
|
||||||
public static function createRequestOptions(PublicKeyCredentialUserEntity $userEntity, string $challenge): PublicKeyCredentialCreationOptions
|
public static function createRequestOptions(PublicKeyCredentialUserEntity $userEntity, string $challenge): PublicKeyCredentialCreationOptions
|
||||||
{
|
{
|
||||||
$publicKeyCredentialParametersList = [
|
$publicKeyCredentialParametersList = [
|
||||||
@ -40,6 +53,53 @@ class WebAuthnService
|
|||||||
return static::$publicKeyCredentialSourceRepositoryInstance;
|
return static::$publicKeyCredentialSourceRepositoryInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getAuthenticatorAssertionResponseValidator(): AuthenticatorAssertionResponseValidator
|
||||||
|
{
|
||||||
|
if (static::$authenticatorAssertionResponseValidator === null) {
|
||||||
|
$algorithmManager = new Manager();
|
||||||
|
$algorithmManager->add(new ES256());
|
||||||
|
$algorithmManager->add(new RS256());
|
||||||
|
static::$authenticatorAssertionResponseValidator = new AuthenticatorAssertionResponseValidator(
|
||||||
|
static::getPublicKeyCredentialSourceRepository(),
|
||||||
|
new IgnoreTokenBindingHandler(),
|
||||||
|
new ExtensionOutputCheckerHandler(),
|
||||||
|
$algorithmManager
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return static::$authenticatorAssertionResponseValidator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAuthenticatorAttestationResponseValidator(): AuthenticatorAttestationResponseValidator
|
||||||
|
{
|
||||||
|
return new AuthenticatorAttestationResponseValidator(
|
||||||
|
static::getAttestationStatementSupportManager(),
|
||||||
|
static::getPublicKeyCredentialSourceRepository(),
|
||||||
|
new IgnoreTokenBindingHandler(),
|
||||||
|
new ExtensionOutputCheckerHandler()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPublicKeyCredentialLoader(): PublicKeyCredentialLoader
|
||||||
|
{
|
||||||
|
return new PublicKeyCredentialLoader(
|
||||||
|
static::getAttestationObjectLoader()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAttestationObjectLoader(): AttestationObjectLoader
|
||||||
|
{
|
||||||
|
return new AttestationObjectLoader(static::getAttestationStatementSupportManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getAttestationStatementSupportManager(): AttestationStatementSupportManager
|
||||||
|
{
|
||||||
|
if (static::$attestationStatementSupportManager === null) {
|
||||||
|
static::$attestationStatementSupportManager = new AttestationStatementSupportManager();
|
||||||
|
static::$attestationStatementSupportManager->add(new NoneAttestationStatementSupport());
|
||||||
|
}
|
||||||
|
return static::$attestationStatementSupportManager;
|
||||||
|
}
|
||||||
|
|
||||||
private static function getRpEntity(): PublicKeyCredentialRpEntity
|
private static function getRpEntity(): PublicKeyCredentialRpEntity
|
||||||
{
|
{
|
||||||
return new PublicKeyCredentialRpEntity(
|
return new PublicKeyCredentialRpEntity(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user