refactoring

This commit is contained in:
Roland Gruber 2019-12-21 15:08:48 +01:00
parent 27a4234634
commit de19770211
3 changed files with 121 additions and 110 deletions

View File

@ -1,5 +1,6 @@
<?php <?php
namespace LAM\LIB\TWO_FACTOR; namespace LAM\LIB\TWO_FACTOR;
use LAM\LOGIN\WEBAUTHN\WebauthnManager;
use \selfServiceProfile; use \selfServiceProfile;
use \LAMConfig; use \LAMConfig;
use \htmlScript; use \htmlScript;
@ -551,7 +552,8 @@ class WebauthnProvider extends BaseProvider {
$row->add(new htmlDiv(null, $errorMessage, array('hidden webauthn-error')), 12); $row->add(new htmlDiv(null, $errorMessage, array('hidden webauthn-error')), 12);
if ($this->config->twoFactorAuthenticationOptional === true) { if ($this->config->twoFactorAuthenticationOptional === true) {
include_once __DIR__ . '/webauthn.inc'; include_once __DIR__ . '/webauthn.inc';
$hasTokens = hasTokensRegistered($userDn); $webauthnManager = new WebauthnManager();
$hasTokens = $webauthnManager->isRegistered($userDn);
if (!$hasTokens) { if (!$hasTokens) {
$skipButton = new htmlButton('skip_webauthn', _('Skip')); $skipButton = new htmlButton('skip_webauthn', _('Skip'));
$skipButton->setCSSClasses(array('fullwidth')); $skipButton->setCSSClasses(array('fullwidth'));
@ -572,7 +574,8 @@ class WebauthnProvider extends BaseProvider {
public function verify2ndFactor($user, $password, $serial, $twoFactorInput) { public function verify2ndFactor($user, $password, $serial, $twoFactorInput) {
logNewMessage(LOG_DEBUG, 'WebauthnProvider: Checking 2nd factor for ' . $user); logNewMessage(LOG_DEBUG, 'WebauthnProvider: Checking 2nd factor for ' . $user);
include_once __DIR__ . '/webauthn.inc'; include_once __DIR__ . '/webauthn.inc';
if ($this->config->twoFactorAuthenticationOptional && !hasTokensRegistered($user) && ($_POST['sig_response'] === 'skip')) { $webauthnManager = new WebauthnManager();
if ($this->config->twoFactorAuthenticationOptional && !$webauthnManager->isRegistered($user) && ($_POST['sig_response'] === 'skip')) {
return true; return true;
} }
$response = base64_decode($_POST['sig_response']); $response = base64_decode($_POST['sig_response']);

View File

@ -72,103 +72,124 @@ use \LAMException;
include_once __DIR__ . '/3rdParty/composer/autoload.php'; include_once __DIR__ . '/3rdParty/composer/autoload.php';
/** /**
* Returns if the given DN is registered for webauthn. * Manages Webauthn registrations and authentications.
* *
* @param string $dn DN * @package LAM\LOGIN\WEBAUTHN
* @return boolean is registered
*/ */
function isRegistered($dn) { class WebauthnManager {
return false;
}
/** /**
* Returns a challenge for a new token. * Returns if the given DN is registered for webauthn.
* *
* @param string $dn DN * @param string $dn DN
* @param bool $isSelfService is executed in self service * @return boolean is registered
* @return PublicKeyCredentialCreationOptions registration object */
*/ public function isRegistered($dn) {
function getRegistrationObject($dn, $isSelfService) { $database = $this->getDatabase();
$rpEntity = createRpEntry($isSelfService); $userEntity = $this->getUserEntity($dn);
$userEntity = getUserEntity($dn); $results = $database->findAllForUserEntity($userEntity);
$challenge = generateRandomPassword(32); return !empty($results);
$credentialParameters = getCredentialParameters();
$excludedKeys = getExcludedKeys($userEntity);
$timeout = 20000;
$registrationObject = new PublicKeyCredentialCreationOptions(
$rpEntity,
$userEntity,
$challenge,
$credentialParameters,
$timeout,
$excludedKeys,
new AuthenticatorSelectionCriteria(),
PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE,
new AuthenticationExtensionsClientInputs());
logNewMessage(LOG_DEBUG, 'Webauthn registration: ' . json_encode($registrationObject));
return $registrationObject;
}
/**
* Returns the part that identifies the server and application.
*
* @param bool $isSelfService is executed in self service
* @return PublicKeyCredentialRpEntity relying party entry
*/
function createRpEntry($isSelfService) {
$pathPrefix = $isSelfService ? '../' : '';
$icon = $pathPrefix . '../graphics/logo136.png';
if (!$isSelfService) {
$domain = $_SESSION['config']->getTwoFactorAuthenticationDomain();
} }
return new PublicKeyCredentialRpEntity(
'LDAP Account Manager', //Name
$domain,
$icon
);
}
/** /**
* Returns the user entity for the registration. * Returns a challenge for a new token.
* *
* @param $dn DN * @param string $dn DN
* @return PublicKeyCredentialUserEntity user entity * @param bool $isSelfService is executed in self service
*/ * @return PublicKeyCredentialCreationOptions registration object
function getUserEntity($dn) { */
return new PublicKeyCredentialUserEntity( public function getRegistrationObject($dn, $isSelfService) {
$dn, $rpEntity = $this->createRpEntry($isSelfService);
$dn, $userEntity = $this->getUserEntity($dn);
extractRDNValue($dn), $challenge = generateRandomPassword(32);
null $credentialParameters = $this->getCredentialParameters();
); $excludedKeys = $this->getExcludedKeys($userEntity);
} $timeout = 20000;
$registrationObject = new PublicKeyCredentialCreationOptions(
/** $rpEntity,
* Returns the supported credential algorithms. $userEntity,
* $challenge,
* @return array algorithms $credentialParameters,
*/ $timeout,
function getCredentialParameters() { $excludedKeys,
return array( new AuthenticatorSelectionCriteria(),
new PublicKeyCredentialParameters('public-key', Algorithms::COSE_ALGORITHM_ES256), PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE,
new PublicKeyCredentialParameters('public-key', Algorithms::COSE_ALGORITHM_RS256), new AuthenticationExtensionsClientInputs());
); logNewMessage(LOG_DEBUG, 'Webauthn registration: ' . json_encode($registrationObject));
} return $registrationObject;
/**
* Returns a list of all credential ids that are already registered.
*
* @param PublicKeyCredentialUserEntity $user user data
* @return PublicKeyCredentialDescriptor[] credential ids
*/
function getExcludedKeys($user) {
$keys = array();
$repository = new PublicKeyCredentialSourceRepositorySQLite();
$credentialSources = $repository->findAllForUserEntity($user);
foreach ($credentialSources as $credentialSource) {
$keys[] = new PublicKeyCredentialDescriptor(PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY, $credentialSource->getPublicKeyCredentialId());
} }
return $keys;
/**
* Returns the user entity for the registration.
*
* @param $dn DN
* @return PublicKeyCredentialUserEntity user entity
*/
private function getUserEntity($dn) {
return new PublicKeyCredentialUserEntity(
$dn,
$dn,
extractRDNValue($dn),
null
);
}
/**
* Returns the part that identifies the server and application.
*
* @param bool $isSelfService is executed in self service
* @return PublicKeyCredentialRpEntity relying party entry
*/
private function createRpEntry($isSelfService) {
$pathPrefix = $isSelfService ? '../' : '';
$icon = $pathPrefix . '../graphics/logo136.png';
if (!$isSelfService) {
$domain = $_SESSION['config']->getTwoFactorAuthenticationDomain();
}
return new PublicKeyCredentialRpEntity(
'LDAP Account Manager', //Name
$domain,
$icon
);
}
/**
* Returns the supported credential algorithms.
*
* @return array algorithms
*/
private function getCredentialParameters() {
return array(
new PublicKeyCredentialParameters('public-key', Algorithms::COSE_ALGORITHM_ES256),
new PublicKeyCredentialParameters('public-key', Algorithms::COSE_ALGORITHM_RS256),
);
}
/**
* Returns a list of all credential ids that are already registered.
*
* @param PublicKeyCredentialUserEntity $user user data
* @return PublicKeyCredentialDescriptor[] credential ids
*/
private function getExcludedKeys($user) {
$keys = array();
$repository = $this->getDatabase();
$credentialSources = $repository->findAllForUserEntity($user);
foreach ($credentialSources as $credentialSource) {
$keys[] = new PublicKeyCredentialDescriptor(PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY, $credentialSource->getPublicKeyCredentialId());
}
return $keys;
}
/**
* Returns the webauthn database.
*
* @return PublicKeyCredentialSourceRepositorySQLite database
*/
public function getDatabase() {
return new PublicKeyCredentialSourceRepositorySQLite();
}
} }
/** /**
@ -275,19 +296,6 @@ function getExtensionOutputChecker() {
return new ExtensionOutputCheckerHandler(); return new ExtensionOutputCheckerHandler();
} }
/**
* Returns if there are any tokens registered for the given DN.
*
* @param string $dn user DN
* @return bool at least one token is registered
*/
function hasTokensRegistered($dn) {
$repository = new PublicKeyCredentialSourceRepositorySQLite();
$userEntity = getUserEntity($dn);
$tokens = $repository->findAllForUserEntity($userEntity);
return !empty($tokens);
}
/** /**
* Stores the public key credentials in the SQLite database. * Stores the public key credentials in the SQLite database.
* *

View File

@ -7,8 +7,7 @@ use \htmlResponsiveRow;
use \htmlLink; use \htmlLink;
use \htmlOutputText; use \htmlOutputText;
use \htmlButton; use \htmlButton;
use function LAM\LOGIN\WEBAUTHN\getRegistrationObject; use LAM\LOGIN\WEBAUTHN\WebauthnManager;
use function LAM\LOGIN\WEBAUTHN\isRegistered;
/* /*
@ -193,9 +192,10 @@ class Ajax {
private function manageWebauthn($isSelfService) { private function manageWebauthn($isSelfService) {
include_once __DIR__ . '/../../lib/webauthn.inc'; include_once __DIR__ . '/../../lib/webauthn.inc';
$userDN = $_SESSION['ldap']->getUserName(); $userDN = $_SESSION['ldap']->getUserName();
$isRegistered = isRegistered($userDN); $webauthnManager = new WebauthnManager();
$isRegistered = $webauthnManager->isRegistered($userDN);
if (!$isRegistered) { if (!$isRegistered) {
$registrationObject = getRegistrationObject($userDN, $isSelfService); $registrationObject = $webauthnManager->getRegistrationObject($userDN, $isSelfService);
$_SESSION['webauthn_registration'] = json_encode($registrationObject); $_SESSION['webauthn_registration'] = json_encode($registrationObject);
echo json_encode( echo json_encode(
array( array(