diff --git a/lam/graphics/webauthn.png b/lam/graphics/webauthn.png new file mode 100644 index 00000000..31072bb2 Binary files /dev/null and b/lam/graphics/webauthn.png differ diff --git a/lam/lib/tools/webauthn.inc b/lam/lib/tools/webauthn.inc new file mode 100644 index 00000000..eb97ec29 --- /dev/null +++ b/lam/lib/tools/webauthn.inc @@ -0,0 +1,133 @@ +getTwoFactorAuthentication() === TwoFactorProviderService::TWO_FACTOR_WEBAUTHN); + } + + /** + * Returns if a tool may be hidden by configuration in the LAM server profile. + * + * @return boolean hideable + */ + function isHideable() { + return true; + } + +} + +?> \ No newline at end of file diff --git a/lam/lib/webauthn.inc b/lam/lib/webauthn.inc index 9b1fabac..21e4fc6b 100644 --- a/lam/lib/webauthn.inc +++ b/lam/lib/webauthn.inc @@ -49,7 +49,7 @@ use \LAMException; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2019 Roland Gruber + Copyright (C) 2019 - 2020 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -546,7 +546,7 @@ class PublicKeyCredentialSourceRepositorySQLite implements PublicKeyCredentialSo $pdo = $this->getPDO(); $statement = $pdo->prepare('select * from ' . self::TABLE_NAME . ' where userId like :searchTerm'); $statement->execute(array( - ':searchTerm' => '%' . $searchTerm . '%' + ':searchTerm' => $searchTerm )); $results = $statement->fetchAll(); $devices = array(); diff --git a/lam/templates/lib/500_lam.js b/lam/templates/lib/500_lam.js index 449b56eb..7a2856b1 100644 --- a/lam/templates/lib/500_lam.js +++ b/lam/templates/lib/500_lam.js @@ -1,7 +1,7 @@ /** This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2003 - 2019 Roland Gruber + Copyright (C) 2003 - 2020 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1581,18 +1581,41 @@ window.lam.webauthn.addDeviceActionListeners = function() { /** * Removes a webauthn device. * - * @param element button + * @param event click event */ window.lam.webauthn.removeDevice = function(event) { event.preventDefault(); const element = jQuery(event.target); + window.lam.webauthn.removeDeviceDialog(element, 'webauthnDevices'); + return false; +} + +/** + * Removes a user's own webauthn device. + * + * @param event click event + */ +window.lam.webauthn.removeOwnDevice = function(event) { + event.preventDefault(); + const element = jQuery(event.target); + window.lam.webauthn.removeDeviceDialog(element, 'webauthnOwnDevices'); + return false; +} + +/** + * Opens the remove device diaog. + * + * @param element delete button + * @param action action for request (delete|deleteOwn) + */ +window.lam.webauthn.removeDeviceDialog = function(element, action) { const dialogTitle = element.data('dialogtitle'); const okText = element.data('oktext'); const cancelText = element.data('canceltext'); let buttonList = {}; buttonList[okText] = function() { jQuery('#webauthnDeleteConfirm').dialog('close'); - window.lam.webauthn.sendRemoveDeviceRequest(element); + window.lam.webauthn.sendRemoveDeviceRequest(element, action); }; buttonList[cancelText] = function() { jQuery(this).dialog("close"); @@ -1604,16 +1627,15 @@ window.lam.webauthn.removeDevice = function(event) { buttons: buttonList, width: 'auto' }); - - return false; } /** * Sends the remove request to server. * * @param element button element + * @param action action (delete|deleteOwn) */ -window.lam.webauthn.sendRemoveDeviceRequest = function(element) { +window.lam.webauthn.sendRemoveDeviceRequest = function(element, action) { const dn = element.data('dn'); const credential = element.data('credential'); const resultDiv = jQuery('#webauthn_results'); @@ -1626,7 +1648,7 @@ window.lam.webauthn.sendRemoveDeviceRequest = function(element) { credentialId: credential }; jQuery.ajax({ - url: '../misc/ajax.php?function=webauthnDevices', + url: '../misc/ajax.php?function=' + action, method: 'POST', data: data }) diff --git a/lam/templates/misc/ajax.php b/lam/templates/misc/ajax.php index f709a544..3cda46f1 100644 --- a/lam/templates/misc/ajax.php +++ b/lam/templates/misc/ajax.php @@ -15,7 +15,7 @@ use \LAMCfgMain; /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) - Copyright (C) 2011 - 2019 Roland Gruber + Copyright (C) 2011 - 2020 Roland Gruber This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -159,6 +159,9 @@ class Ajax { ob_end_clean(); echo $jsonOut; } + elseif ($function === 'webauthnOwnDevices') { + $this->manageWebauthnOwnDevices(); + } } /** @@ -255,7 +258,7 @@ class Ajax { private function manageWebauthnDevicesSearch($searchTerm) { include_once __DIR__ . '/../../lib/webauthn.inc'; $database = new \LAM\LOGIN\WEBAUTHN\PublicKeyCredentialSourceRepositorySQLite(); - $results = $database->searchDevices($searchTerm); + $results = $database->searchDevices('%' . $searchTerm . '%'); $row = new htmlResponsiveRow(); $row->addVerticalSpacer('0.5rem'); if (empty($results)) { @@ -326,6 +329,23 @@ class Ajax { echo json_encode(array('content' => $content)); } + /** + * Manages requests to setup user's own webauthn devices. + */ + private function manageWebauthnOwnDevices() { + $action = $_POST['action']; + $dn = $_POST['dn']; + $sessionDn = $_SESSION['ldap']->getUserName(); + if ($sessionDn !== $dn) { + logNewMessage(LOG_ERR, 'Webauthn delete canceled, DN does not match.'); + die(); + } + if ($action === 'delete') { + $credentialId = $_POST['credentialId']; + $this->manageWebauthnDevicesDelete($dn, $credentialId); + } + } + /** * Handles DN selection fields. * diff --git a/lam/templates/tools/webauthn.php b/lam/templates/tools/webauthn.php new file mode 100644 index 00000000..3b81b592 --- /dev/null +++ b/lam/templates/tools/webauthn.php @@ -0,0 +1,117 @@ +'; +echo "
'; +echo ''; +include __DIR__ . '/../../lib/adminFooter.inc'; + +?> diff --git a/lam/tests/lib/webauthnDbTest.php b/lam/tests/lib/webauthnDbTest.php index d6478b19..1d597564 100644 --- a/lam/tests/lib/webauthnDbTest.php +++ b/lam/tests/lib/webauthnDbTest.php @@ -148,8 +148,9 @@ class PublicKeyCredentialSourceRepositorySQLiteTest extends TestCase { "uh1", 1); $this->database->saveCredentialSource($source1); - $this->assertNotEmpty($this->database->searchDevices('h1')); - $this->assertEmpty($this->database->searchDevices('h2')); + $this->assertNotEmpty($this->database->searchDevices('uh1')); + $this->assertNotEmpty($this->database->searchDevices('%h1%')); + $this->assertEmpty($this->database->searchDevices('uh2')); } public function test_deleteDevice() {