From 691055b83eb4e13172bca76802254cd077c371aa Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sat, 11 Jan 2020 17:29:05 +0100 Subject: [PATCH] webauthn --- lam/lib/webauthn.inc | 23 +++++++++++++-- lam/templates/lib/500_lam.js | 50 ++++++++++++++++++++++++-------- lam/templates/tools/webauthn.php | 2 +- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/lam/lib/webauthn.inc b/lam/lib/webauthn.inc index a41d0f34..bcf1e097 100644 --- a/lam/lib/webauthn.inc +++ b/lam/lib/webauthn.inc @@ -100,14 +100,15 @@ class WebauthnManager { * * @param string $dn DN * @param bool $isSelfService is executed in self service + * @param array $extraExcludedKeys credentialIds that should be added to excluded keys * @return PublicKeyCredentialCreationOptions registration object */ - public function getRegistrationObject($dn, $isSelfService) { + public function getRegistrationObject($dn, $isSelfService, $extraExcludedKeys = array()) { $rpEntity = $this->createRpEntry($isSelfService); $userEntity = $this->getUserEntity($dn); $challenge = $this->createChallenge(); $credentialParameters = $this->getCredentialParameters(); - $excludedKeys = $this->getExcludedKeys($userEntity); + $excludedKeys = $this->getExcludedKeys($userEntity, $extraExcludedKeys); $timeout = $this->getTimeout(); $registrationObject = new PublicKeyCredentialCreationOptions( $rpEntity, @@ -161,6 +162,18 @@ class WebauthnManager { return false; } + /** + * Returns a public key credential loader. + * + * @return PublicKeyCredentialLoader public key credential loader + */ + public function createPublicKeyCredentialLoader() { + $decoder = $this->getCborDecoder(); + $attestationSupportManager = $this->getAttestationSupportManager($decoder); + $attestationObjectLoader = $this->getAttestationObjectLoader($attestationSupportManager, $decoder); + return $this->getPublicKeyCredentialLoader($attestationObjectLoader, $decoder); + } + /** * Returns the user entity for the registration. * @@ -214,15 +227,19 @@ class WebauthnManager { * Returns a list of all credential ids that are already registered. * * @param PublicKeyCredentialUserEntity $user user data + * @param array $extraExcludedKeys credentialIds that should be added to excluded keys * @return PublicKeyCredentialDescriptor[] credential ids */ - private function getExcludedKeys($user) { + private function getExcludedKeys($user, $extraExcludedKeys = array()) { $keys = array(); $repository = $this->getDatabase(); $credentialSources = $repository->findAllForUserEntity($user); foreach ($credentialSources as $credentialSource) { $keys[] = new PublicKeyCredentialDescriptor(PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY, $credentialSource->getPublicKeyCredentialId()); } + foreach ($extraExcludedKeys as $extraExcludedKey) { + $keys[] = new PublicKeyCredentialDescriptor(PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY, $extraExcludedKey); + } return $keys; } diff --git a/lam/templates/lib/500_lam.js b/lam/templates/lib/500_lam.js index 053b8aa0..3c7c782d 100644 --- a/lam/templates/lib/500_lam.js +++ b/lam/templates/lib/500_lam.js @@ -1620,15 +1620,18 @@ window.lam.webauthn.removeDevice = function(event) { window.lam.webauthn.removeOwnDevice = function(event, isSelfService) { event.preventDefault(); const element = jQuery(event.currentTarget); - const successCallback = function () { - const form = jQuery("#webauthnform"); - jQuery('').attr({ - type: 'hidden', - name: 'removed', - value: 'true' - }).appendTo(form); - form.submit(); - }; + let successCallback = null; + if (!isSelfService) { + successCallback = function () { + const form = jQuery("#webauthnform"); + jQuery('').attr({ + type: 'hidden', + name: 'removed', + value: 'true' + }).appendTo(form); + form.submit(); + }; + } let action = 'webauthnOwnDevices'; if (isSelfService) { action = action + '&selfservice=true&module=webauthn&scope=user'; @@ -1706,21 +1709,44 @@ window.lam.webauthn.sendRemoveDeviceRequest = function(element, action, successC * Registers a user's own webauthn device. * * @param event click event + * @param isSelfService runs in self service context */ -window.lam.webauthn.registerOwnDevice = function(event) { +window.lam.webauthn.registerOwnDevice = function(event, isSelfService) { event.preventDefault(); const element = jQuery(event.target); const dn = element.data('dn'); const tokenValue = element.data('sec_token_value'); - const tokenName = element.data('sec_token_name'); const publicKey = element.data('publickey'); - const successCallback = function (publicKeyCredential) { + let successCallback = function (publicKeyCredential) { const form = jQuery("#webauthnform"); const response = btoa(JSON.stringify(publicKeyCredential)); const registrationData = jQuery('#registrationData'); registrationData.val(response); form.submit(); }; + if (isSelfService) { + successCallback = function (publicKeyCredential) { + const data = { + action: 'register', + jsonInput: '', + sec_token: tokenValue, + dn: dn, + credential: btoa(JSON.stringify(publicKeyCredential)) + }; + jQuery.ajax({ + url: '../misc/ajax.php?selfservice=true&module=webauthn&scope=user', + method: 'POST', + data: data + }) + .done(function(jsonData) { + const resultDiv = jQuery('#webauthn_results'); + resultDiv.html(jsonData.content); + }) + .fail(function() { + console.log('Webauthn device registration failed'); + }); + }; + } const errorCallback = function (error) { let errorDiv = jQuery('#generic-webauthn-error'); let buttonLabel = errorDiv.data('button'); diff --git a/lam/templates/tools/webauthn.php b/lam/templates/tools/webauthn.php index 04147ada..1b9e23f5 100644 --- a/lam/templates/tools/webauthn.php +++ b/lam/templates/tools/webauthn.php @@ -88,7 +88,7 @@ $registrationJson = json_encode($registration); $_SESSION['webauthn_registration'] = $registrationJson; $registerButton->addDataAttribute('publickey', $registrationJson); $registerButton->setIconClass('createButton'); -$registerButton->setOnClick('window.lam.webauthn.registerOwnDevice(event);'); +$registerButton->setOnClick('window.lam.webauthn.registerOwnDevice(event, false);'); $buttonGroup->addElement($registerButton); $buttonGroup->addElement(new htmlSpacer('1rem', null)); $reloadButton = new htmlButton('reload', _('Reload'));