Skip to content

Instantly share code, notes, and snippets.

@Chenx221
Created March 17, 2024 09:11
Show Gist options
  • Save Chenx221/f7b5acb5b16704cfd734214a3e578cfa to your computer and use it in GitHub Desktop.
Save Chenx221/f7b5acb5b16704cfd734214a3e578cfa to your computer and use it in GitHub Desktop.
Yii2, Webauthn Framework (Part 1)
public function actionCreateCredentialOptions(): Response
{
$id = Yii::$app->params['domain'];
$user = Yii::$app->user->identity;
$rpEntity = PublicKeyCredentialRpEntity::create(
'NetDisk Application',
$id
);
$userEntity = PublicKeyCredentialUserEntity::create(
$user->username,
$user->id,
$user->name,
);
$challenge = random_bytes(16);
$publicKeyCredentialCreationOptions =
PublicKeyCredentialCreationOptions::create(
$rpEntity,
$userEntity,
$challenge
);
Yii::$app->session->set('publicKeyCredentialCreationOptions', $publicKeyCredentialCreationOptions);
return $this->asJson($publicKeyCredentialCreationOptions);
}
public function actionCreateCredential(): Response
{
$data = Yii::$app->request->getRawBody();
$json_decode = json_decode($data, true);
$fido_name = empty($json_decode['fido_name']) ? 'Unknown' : $json_decode['fido_name'];
$attestationStatementSupportManager = AttestationStatementSupportManager::create();
$attestationStatementSupportManager->add(NoneAttestationStatementSupport::create());
$webauthnSerializerFactory = new WebauthnSerializerFactory($attestationStatementSupportManager);
$serializer = $webauthnSerializerFactory->create();
$publicKeyCredential = $serializer->deserialize($data, PublicKeyCredential::class, 'json');
$authenticatorAttestationResponse = $publicKeyCredential->response;
if (!$authenticatorAttestationResponse instanceof AuthenticatorAttestationResponse) {
return $this->asJson(['message' => 'Invalid response type']);
}
// 什么时候更新开发文档?
$ceremonyStepManagerFactory = new CeremonyStepManagerFactory();
$ceremonyStepManager = $ceremonyStepManagerFactory->creationCeremony();
$authenticatorAttestationResponseValidator = AuthenticatorAttestationResponseValidator::create(
null,
null,
null,
null,
null,
$ceremonyStepManager
);
$publicKeyCredentialCreationOptions = Yii::$app->session->get('publicKeyCredentialCreationOptions');
try {
$publicKeyCredentialSource = $authenticatorAttestationResponseValidator->check(
$authenticatorAttestationResponse,
$publicKeyCredentialCreationOptions,
Yii::$app->params['domain']
);
$publicKeyCredentialSourceRepository = new PublicKeyCredentialSourceRepository();
$publicKeyCredentialSourceRepository->saveCredential($publicKeyCredentialSource, $fido_name);
return $this->asJson(['verified' => true]);
} catch (Throwable $e) {
return $this->asJson(['message' => $e->getMessage(), 'verified' => false]);
}
}
public function actionRequestAssertionOptions(): Response
{
$user = Yii::$app->user->identity;
$publicKeyCredentialSourceRepository = new PublicKeyCredentialSourceRepository();
$registeredAuthenticators = $publicKeyCredentialSourceRepository->findAllForUserEntity($user);
$allowedCredentials = array_map(
static function (PublicKeyCredentialSourceRepository $credential): PublicKeyCredentialDescriptor {
$data = $credential->data;
$webauthnSerializerFactory = new WebauthnSerializerFactory(new AttestationStatementSupportManager());
$publicKeyCredentialSource = $webauthnSerializerFactory->create()->deserialize($data, PublicKeyCredentialSource::class, 'json');
return $publicKeyCredentialSource->getPublicKeyCredentialDescriptor();
},
$registeredAuthenticators
);
$publicKeyCredentialRequestOptions =
PublicKeyCredentialRequestOptions::create(
random_bytes(32), // Challenge
allowCredentials: $allowedCredentials
);
Yii::$app->session->set('publicKeyCredentialRequestOptions', $publicKeyCredentialRequestOptions);
return $this->asJson($publicKeyCredentialRequestOptions);
}
public function actionVerifyAssertion(): Response
{
$data = Yii::$app->request->getRawBody();
$attestationStatementSupportManager = AttestationStatementSupportManager::create();
$attestationStatementSupportManager->add(NoneAttestationStatementSupport::create());
$webauthnSerializerFactory = new WebauthnSerializerFactory($attestationStatementSupportManager);
$serializer = $webauthnSerializerFactory->create();
$publicKeyCredential = $serializer->deserialize($data, PublicKeyCredential::class, 'json');
$authenticatorAssertionResponse = $publicKeyCredential->response;
if (!$authenticatorAssertionResponse instanceof AuthenticatorAssertionResponse) {
return $this->asJson(['message' => 'Invalid response type']);
}
$publicKeyCredentialSourceRepository = new PublicKeyCredentialSourceRepository();
$publicKeyCredentialSourceRepository1 = $publicKeyCredentialSourceRepository->findOneByCredentialId(
$publicKeyCredential->id
);
if ($publicKeyCredentialSourceRepository1 === null) {
return $this->asJson(['message' => 'Invalid credential']);
}
$PKCS = $webauthnSerializerFactory->create()->deserialize($publicKeyCredentialSourceRepository1->data, PublicKeyCredentialSource::class, 'json');
$ceremonyStepManagerFactory = new CeremonyStepManagerFactory();
$ceremonyStepManager = $ceremonyStepManagerFactory->requestCeremony();
$authenticatorAssertionResponseValidator = AuthenticatorAssertionResponseValidator::create(
null,
null,
null,
null,
null,
$ceremonyStepManager
);
$publicKeyCredentialRequestOptions = Yii::$app->session->get('publicKeyCredentialRequestOptions');
try {
$publicKeyCredentialSource = $authenticatorAssertionResponseValidator->check(
$PKCS, //credential source
$authenticatorAssertionResponse, //user response
$publicKeyCredentialRequestOptions,
Yii::$app->params['domain'],
$publicKeyCredentialSourceRepository1->user_id
);
} catch (AuthenticatorResponseVerificationException $e) {
return $this->asJson(['message' => $e->getMessage(), 'verified' => false]);
}
// Optional, but highly recommended, you can save the credential source as it may be modified
// during the verification process (counter may be higher).
$publicKeyCredentialSourceRepository1->saveCredential($publicKeyCredentialSource, '',false);
return $this->asJson(['verified' => true]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment