support skipping of 2FA
This commit is contained in:
parent
9086f5847e
commit
9208cb2349
|
@ -11,6 +11,7 @@ use \htmlStatusMessage;
|
||||||
use \htmlDiv;
|
use \htmlDiv;
|
||||||
use \LAMException;
|
use \LAMException;
|
||||||
use Webauthn\PublicKeyCredentialCreationOptions;
|
use Webauthn\PublicKeyCredentialCreationOptions;
|
||||||
|
use function LAM\LOGIN\WEBAUTHN\hasTokensRegistered;
|
||||||
use function LAM\LOGIN\WEBAUTHN\storeNewRegistration;
|
use function LAM\LOGIN\WEBAUTHN\storeNewRegistration;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -547,6 +548,15 @@ class WebauthnProvider extends BaseProvider {
|
||||||
$row->add($loginButton, 12);
|
$row->add($loginButton, 12);
|
||||||
$errorMessage = new htmlStatusMessage('ERROR', '', _('This service requires a browser with "WebAuthn" support.'));
|
$errorMessage = new htmlStatusMessage('ERROR', '', _('This service requires a browser with "WebAuthn" support.'));
|
||||||
$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) {
|
||||||
|
include_once __DIR__ . '/webauthn.inc';
|
||||||
|
$hasTokens = hasTokensRegistered($userDn);
|
||||||
|
if (!$hasTokens) {
|
||||||
|
$skipButton = new htmlButton('skip_webauthn', _('Skip'));
|
||||||
|
$skipButton->setCSSClasses(array('fullwidth'));
|
||||||
|
$row->add($skipButton, 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
$row->add(new htmlJavaScript('window.lam.webauthn.start(\'' . $pathPrefix . '\');'), 0);
|
$row->add(new htmlJavaScript('window.lam.webauthn.start(\'' . $pathPrefix . '\');'), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,8 +566,12 @@ 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);
|
||||||
$response = base64_decode($_POST['sig_response']);
|
|
||||||
include_once __DIR__ . '/webauthn.inc';
|
include_once __DIR__ . '/webauthn.inc';
|
||||||
|
logNewMessage(LOG_ERR, $user);
|
||||||
|
if ($this->config->twoFactorAuthenticationOptional && !hasTokensRegistered($user) && ($_POST['sig_response'] === 'skip')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$response = base64_decode($_POST['sig_response']);
|
||||||
$registrationObject = PublicKeyCredentialCreationOptions::createFromString($_SESSION['webauthn_registration']);
|
$registrationObject = PublicKeyCredentialCreationOptions::createFromString($_SESSION['webauthn_registration']);
|
||||||
if (storeNewRegistration($registrationObject, $response)) {
|
if (storeNewRegistration($registrationObject, $response)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -634,6 +648,7 @@ class TwoFactorProviderService {
|
||||||
$tfConfig->isSelfService = true;
|
$tfConfig->isSelfService = true;
|
||||||
$tfConfig->twoFactorAuthentication = $profile->twoFactorAuthentication;
|
$tfConfig->twoFactorAuthentication = $profile->twoFactorAuthentication;
|
||||||
$tfConfig->twoFactorAuthenticationInsecure = $profile->twoFactorAuthenticationInsecure;
|
$tfConfig->twoFactorAuthenticationInsecure = $profile->twoFactorAuthenticationInsecure;
|
||||||
|
$tfConfig->twoFactorAuthenticationOptional = $profile->twoFactorAuthenticationOptional;
|
||||||
if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) {
|
if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) {
|
||||||
$tfConfig->twoFactorAuthenticationURL = explode("\r\n", $profile->twoFactorAuthenticationURL);
|
$tfConfig->twoFactorAuthenticationURL = explode("\r\n", $profile->twoFactorAuthenticationURL);
|
||||||
}
|
}
|
||||||
|
@ -673,6 +688,7 @@ class TwoFactorProviderService {
|
||||||
$tfConfig->isSelfService = false;
|
$tfConfig->isSelfService = false;
|
||||||
$tfConfig->twoFactorAuthentication = $conf->getTwoFactorAuthentication();
|
$tfConfig->twoFactorAuthentication = $conf->getTwoFactorAuthentication();
|
||||||
$tfConfig->twoFactorAuthenticationInsecure = $conf->getTwoFactorAuthenticationInsecure();
|
$tfConfig->twoFactorAuthenticationInsecure = $conf->getTwoFactorAuthenticationInsecure();
|
||||||
|
$tfConfig->twoFactorAuthenticationOptional = $conf->getTwoFactorAuthenticationOptional();
|
||||||
if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) {
|
if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) {
|
||||||
$tfConfig->twoFactorAuthenticationURL = explode("\r\n", $conf->getTwoFactorAuthenticationURL());
|
$tfConfig->twoFactorAuthenticationURL = explode("\r\n", $conf->getTwoFactorAuthenticationURL());
|
||||||
}
|
}
|
||||||
|
@ -741,4 +757,9 @@ class TwoFactorConfiguration {
|
||||||
*/
|
*/
|
||||||
public $twoFactorAuthenticationSerialAttributeName = null;
|
public $twoFactorAuthenticationSerialAttributeName = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool 2FA is optional
|
||||||
|
*/
|
||||||
|
public $twoFactorAuthenticationOptional = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2480,7 +2480,7 @@ class LAMConfig {
|
||||||
* @return bool 2nd factor is optional
|
* @return bool 2nd factor is optional
|
||||||
*/
|
*/
|
||||||
public function getTwoFactorAuthenticationOptional() {
|
public function getTwoFactorAuthenticationOptional() {
|
||||||
return $this->twoFactorAuthenticationOptional;
|
return boolval($this->twoFactorAuthenticationOptional);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -274,6 +274,19 @@ 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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -479,7 +479,7 @@ if (extension_loaded('curl')) {
|
||||||
TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURL', 'twoFactorAttribute', 'twoFactorDomain'),
|
TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURL', 'twoFactorAttribute', 'twoFactorDomain'),
|
||||||
TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURLs', 'twoFactorOptional', 'twoFactorInsecure', 'twoFactorLabel', 'twoFactorDomain'),
|
TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURLs', 'twoFactorOptional', 'twoFactorInsecure', 'twoFactorLabel', 'twoFactorDomain'),
|
||||||
TwoFactorProviderService::TWO_FACTOR_WEBAUTHN => array('twoFactorURL', 'twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel',
|
TwoFactorProviderService::TWO_FACTOR_WEBAUTHN => array('twoFactorURL', 'twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel',
|
||||||
'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'),
|
'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'),
|
||||||
));
|
));
|
||||||
$twoFactorSelect->setTableRowsToShow(array(
|
$twoFactorSelect->setTableRowsToShow(array(
|
||||||
TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel',
|
TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel',
|
||||||
|
@ -488,7 +488,7 @@ if (extension_loaded('curl')) {
|
||||||
'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey'),
|
'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey'),
|
||||||
TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURL', 'twoFactorLabel',
|
TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURL', 'twoFactorLabel',
|
||||||
'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'),
|
'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'),
|
||||||
TwoFactorProviderService::TWO_FACTOR_WEBAUTHN => array('twoFactorDomain')
|
TwoFactorProviderService::TWO_FACTOR_WEBAUTHN => array('twoFactorDomain', 'twoFactorOptional')
|
||||||
));
|
));
|
||||||
$row->add($twoFactorSelect, 12);
|
$row->add($twoFactorSelect, 12);
|
||||||
$twoFactorAttribute = new htmlResponsiveInputField(_("User name attribute"), 'twoFactorAttribute', $conf->getTwoFactorAuthenticationAttribute(), '528');
|
$twoFactorAttribute = new htmlResponsiveInputField(_("User name attribute"), 'twoFactorAttribute', $conf->getTwoFactorAuthenticationAttribute(), '528');
|
||||||
|
|
|
@ -1377,6 +1377,12 @@ window.lam.webauthn.start = function(prefix) {
|
||||||
* @param prefix path prefix for Ajax endpoint
|
* @param prefix path prefix for Ajax endpoint
|
||||||
*/
|
*/
|
||||||
window.lam.webauthn.run = function(prefix) {
|
window.lam.webauthn.run = function(prefix) {
|
||||||
|
jQuery('#btn_skip_webauthn').click(function () {
|
||||||
|
let form = jQuery("#2faform");
|
||||||
|
form.append('<input type="hidden" name="sig_response" value="skip"/>');
|
||||||
|
form.submit();
|
||||||
|
return;
|
||||||
|
});
|
||||||
var token = jQuery('#sec_token').val();
|
var token = jQuery('#sec_token').val();
|
||||||
// check for webauthn support
|
// check for webauthn support
|
||||||
if (!navigator.credentials || (typeof(PublicKeyCredential) === "undefined")) {
|
if (!navigator.credentials || (typeof(PublicKeyCredential) === "undefined")) {
|
||||||
|
|
Loading…
Reference in New Issue