This commit is contained in:
Roland Gruber 2020-01-11 17:29:05 +01:00
parent 286e447553
commit 691055b83e
3 changed files with 59 additions and 16 deletions

View File

@ -100,14 +100,15 @@ class WebauthnManager {
* *
* @param string $dn DN * @param string $dn DN
* @param bool $isSelfService is executed in self service * @param bool $isSelfService is executed in self service
* @param array $extraExcludedKeys credentialIds that should be added to excluded keys
* @return PublicKeyCredentialCreationOptions registration object * @return PublicKeyCredentialCreationOptions registration object
*/ */
public function getRegistrationObject($dn, $isSelfService) { public function getRegistrationObject($dn, $isSelfService, $extraExcludedKeys = array()) {
$rpEntity = $this->createRpEntry($isSelfService); $rpEntity = $this->createRpEntry($isSelfService);
$userEntity = $this->getUserEntity($dn); $userEntity = $this->getUserEntity($dn);
$challenge = $this->createChallenge(); $challenge = $this->createChallenge();
$credentialParameters = $this->getCredentialParameters(); $credentialParameters = $this->getCredentialParameters();
$excludedKeys = $this->getExcludedKeys($userEntity); $excludedKeys = $this->getExcludedKeys($userEntity, $extraExcludedKeys);
$timeout = $this->getTimeout(); $timeout = $this->getTimeout();
$registrationObject = new PublicKeyCredentialCreationOptions( $registrationObject = new PublicKeyCredentialCreationOptions(
$rpEntity, $rpEntity,
@ -161,6 +162,18 @@ class WebauthnManager {
return false; 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. * Returns the user entity for the registration.
* *
@ -214,15 +227,19 @@ class WebauthnManager {
* Returns a list of all credential ids that are already registered. * Returns a list of all credential ids that are already registered.
* *
* @param PublicKeyCredentialUserEntity $user user data * @param PublicKeyCredentialUserEntity $user user data
* @param array $extraExcludedKeys credentialIds that should be added to excluded keys
* @return PublicKeyCredentialDescriptor[] credential ids * @return PublicKeyCredentialDescriptor[] credential ids
*/ */
private function getExcludedKeys($user) { private function getExcludedKeys($user, $extraExcludedKeys = array()) {
$keys = array(); $keys = array();
$repository = $this->getDatabase(); $repository = $this->getDatabase();
$credentialSources = $repository->findAllForUserEntity($user); $credentialSources = $repository->findAllForUserEntity($user);
foreach ($credentialSources as $credentialSource) { foreach ($credentialSources as $credentialSource) {
$keys[] = new PublicKeyCredentialDescriptor(PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY, $credentialSource->getPublicKeyCredentialId()); $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; return $keys;
} }

View File

@ -1620,7 +1620,9 @@ window.lam.webauthn.removeDevice = function(event) {
window.lam.webauthn.removeOwnDevice = function(event, isSelfService) { window.lam.webauthn.removeOwnDevice = function(event, isSelfService) {
event.preventDefault(); event.preventDefault();
const element = jQuery(event.currentTarget); const element = jQuery(event.currentTarget);
const successCallback = function () { let successCallback = null;
if (!isSelfService) {
successCallback = function () {
const form = jQuery("#webauthnform"); const form = jQuery("#webauthnform");
jQuery('<input>').attr({ jQuery('<input>').attr({
type: 'hidden', type: 'hidden',
@ -1629,6 +1631,7 @@ window.lam.webauthn.removeOwnDevice = function(event, isSelfService) {
}).appendTo(form); }).appendTo(form);
form.submit(); form.submit();
}; };
}
let action = 'webauthnOwnDevices'; let action = 'webauthnOwnDevices';
if (isSelfService) { if (isSelfService) {
action = action + '&selfservice=true&module=webauthn&scope=user'; 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. * Registers a user's own webauthn device.
* *
* @param event click event * @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(); event.preventDefault();
const element = jQuery(event.target); const element = jQuery(event.target);
const dn = element.data('dn'); const dn = element.data('dn');
const tokenValue = element.data('sec_token_value'); const tokenValue = element.data('sec_token_value');
const tokenName = element.data('sec_token_name');
const publicKey = element.data('publickey'); const publicKey = element.data('publickey');
const successCallback = function (publicKeyCredential) { let successCallback = function (publicKeyCredential) {
const form = jQuery("#webauthnform"); const form = jQuery("#webauthnform");
const response = btoa(JSON.stringify(publicKeyCredential)); const response = btoa(JSON.stringify(publicKeyCredential));
const registrationData = jQuery('#registrationData'); const registrationData = jQuery('#registrationData');
registrationData.val(response); registrationData.val(response);
form.submit(); 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) { const errorCallback = function (error) {
let errorDiv = jQuery('#generic-webauthn-error'); let errorDiv = jQuery('#generic-webauthn-error');
let buttonLabel = errorDiv.data('button'); let buttonLabel = errorDiv.data('button');

View File

@ -88,7 +88,7 @@ $registrationJson = json_encode($registration);
$_SESSION['webauthn_registration'] = $registrationJson; $_SESSION['webauthn_registration'] = $registrationJson;
$registerButton->addDataAttribute('publickey', $registrationJson); $registerButton->addDataAttribute('publickey', $registrationJson);
$registerButton->setIconClass('createButton'); $registerButton->setIconClass('createButton');
$registerButton->setOnClick('window.lam.webauthn.registerOwnDevice(event);'); $registerButton->setOnClick('window.lam.webauthn.registerOwnDevice(event, false);');
$buttonGroup->addElement($registerButton); $buttonGroup->addElement($registerButton);
$buttonGroup->addElement(new htmlSpacer('1rem', null)); $buttonGroup->addElement(new htmlSpacer('1rem', null));
$reloadButton = new htmlButton('reload', _('Reload')); $reloadButton = new htmlButton('reload', _('Reload'));