webauthn
This commit is contained in:
parent
9637c2dff6
commit
1535bf4da6
|
@ -329,6 +329,8 @@ $helpArray = array (
|
||||||
"Text" => _('This text is displayed as footer on the self service main page.')),
|
"Text" => _('This text is displayed as footer on the self service main page.')),
|
||||||
"528" => array ("Headline" => _('User name attribute'),
|
"528" => array ("Headline" => _('User name attribute'),
|
||||||
"Text" => _('The attribute (e.g. "uid") that contains the user name for the 2-factor service.')),
|
"Text" => _('The attribute (e.g. "uid") that contains the user name for the 2-factor service.')),
|
||||||
|
"529" => array ("Headline" => _('Domain'),
|
||||||
|
"Text" => _('Please enter the webauthn domain. This is the public domain of the webserver (e.g. "example.com"). Do not include protocol or port.')),
|
||||||
"550" => array ("Headline" => _("From address"),
|
"550" => array ("Headline" => _("From address"),
|
||||||
"Text" => _("This email address will be set as sender address of all password mails. If empty the system default (php.ini) will be used.")),
|
"Text" => _("This email address will be set as sender address of all password mails. If empty the system default (php.ini) will be used.")),
|
||||||
"551" => array ("Headline" => _("Subject"),
|
"551" => array ("Headline" => _("Subject"),
|
||||||
|
|
|
@ -607,6 +607,7 @@ class LAMConfig {
|
||||||
private $twoFactorAuthenticationURL = 'https://localhost';
|
private $twoFactorAuthenticationURL = 'https://localhost';
|
||||||
private $twoFactorAuthenticationClientId = null;
|
private $twoFactorAuthenticationClientId = null;
|
||||||
private $twoFactorAuthenticationSecretKey = null;
|
private $twoFactorAuthenticationSecretKey = null;
|
||||||
|
private $twoFactorAuthenticationDomain = null;
|
||||||
private $twoFactorAuthenticationInsecure = false;
|
private $twoFactorAuthenticationInsecure = false;
|
||||||
private $twoFactorAuthenticationLabel = null;
|
private $twoFactorAuthenticationLabel = null;
|
||||||
private $twoFactorAuthenticationOptional = false;
|
private $twoFactorAuthenticationOptional = false;
|
||||||
|
@ -625,7 +626,7 @@ class LAMConfig {
|
||||||
'scriptUserName', 'scriptSSHKey', 'scriptSSHKeyPassword', 'twoFactorAuthentication', 'twoFactorAuthenticationURL',
|
'scriptUserName', 'scriptSSHKey', 'scriptSSHKeyPassword', 'twoFactorAuthentication', 'twoFactorAuthenticationURL',
|
||||||
'twoFactorAuthenticationInsecure', 'twoFactorAuthenticationLabel', 'twoFactorAuthenticationOptional',
|
'twoFactorAuthenticationInsecure', 'twoFactorAuthenticationLabel', 'twoFactorAuthenticationOptional',
|
||||||
'twoFactorAuthenticationCaption', 'twoFactorAuthenticationClientId', 'twoFactorAuthenticationSecretKey',
|
'twoFactorAuthenticationCaption', 'twoFactorAuthenticationClientId', 'twoFactorAuthenticationSecretKey',
|
||||||
'twoFactorAuthenticationAttribute', 'referentialIntegrityOverlay'
|
'twoFactorAuthenticationDomain', 'twoFactorAuthenticationAttribute', 'referentialIntegrityOverlay'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -991,6 +992,9 @@ class LAMConfig {
|
||||||
if (!in_array("twoFactorAuthenticationSecretKey", $saved)) {
|
if (!in_array("twoFactorAuthenticationSecretKey", $saved)) {
|
||||||
array_push($file_array, "\n" . "twoFactorAuthenticationSecretKey: " . $this->twoFactorAuthenticationSecretKey . "\n");
|
array_push($file_array, "\n" . "twoFactorAuthenticationSecretKey: " . $this->twoFactorAuthenticationSecretKey . "\n");
|
||||||
}
|
}
|
||||||
|
if (!in_array("twoFactorAuthenticationDomain", $saved)) {
|
||||||
|
array_push($file_array, "\n" . "twoFactorAuthenticationDomain: " . $this->twoFactorAuthenticationDomain . "\n");
|
||||||
|
}
|
||||||
if (!in_array("twoFactorAuthenticationInsecure", $saved)) {
|
if (!in_array("twoFactorAuthenticationInsecure", $saved)) {
|
||||||
array_push($file_array, "\n" . "twoFactorAuthenticationInsecure: " . $this->twoFactorAuthenticationInsecure . "\n");
|
array_push($file_array, "\n" . "twoFactorAuthenticationInsecure: " . $this->twoFactorAuthenticationInsecure . "\n");
|
||||||
}
|
}
|
||||||
|
@ -2416,6 +2420,24 @@ class LAMConfig {
|
||||||
return $this->twoFactorAuthenticationSecretKey;
|
return $this->twoFactorAuthenticationSecretKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the domain.
|
||||||
|
*
|
||||||
|
* @param string $domain domain
|
||||||
|
*/
|
||||||
|
public function setTwoFactorAuthenticationDomain($domain) {
|
||||||
|
$this->twoFactorAuthenticationDomain = $domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the domain.
|
||||||
|
*
|
||||||
|
* @return string domain
|
||||||
|
*/
|
||||||
|
public function getTwoFactorAuthenticationDomain() {
|
||||||
|
return $this->twoFactorAuthenticationDomain;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if SSL certificate verification is turned off.
|
* Returns if SSL certificate verification is turned off.
|
||||||
*
|
*
|
||||||
|
|
|
@ -51,10 +51,11 @@ function isRegistered($dn) {
|
||||||
* Returns a challenge for a new token.
|
* Returns a challenge for a new token.
|
||||||
*
|
*
|
||||||
* @param string $dn DN
|
* @param string $dn DN
|
||||||
|
* @param bool $isSelfService is executed in self service
|
||||||
* @return PublicKeyCredentialCreationOptions challenge
|
* @return PublicKeyCredentialCreationOptions challenge
|
||||||
*/
|
*/
|
||||||
function getRegistrationObject($dn) {
|
function getRegistrationObject($dn, $isSelfService) {
|
||||||
$rpEntity = createRpEntry();
|
$rpEntity = createRpEntry($isSelfService);
|
||||||
$userEntity = getUserEntity($dn);
|
$userEntity = getUserEntity($dn);
|
||||||
$challenge = generateRandomPassword(32);
|
$challenge = generateRandomPassword(32);
|
||||||
$credentialParameters = getCredentialParameters();
|
$credentialParameters = getCredentialParameters();
|
||||||
|
@ -76,13 +77,19 @@ function getRegistrationObject($dn) {
|
||||||
/**
|
/**
|
||||||
* Returns the part that identifies the server and application.
|
* Returns the part that identifies the server and application.
|
||||||
*
|
*
|
||||||
|
* @param bool $isSelfService is executed in self service
|
||||||
* @return PublicKeyCredentialRpEntity relying party entry
|
* @return PublicKeyCredentialRpEntity relying party entry
|
||||||
*/
|
*/
|
||||||
function createRpEntry() {
|
function createRpEntry($isSelfService) {
|
||||||
|
$pathPrefix = $isSelfService ? '../' : '';
|
||||||
|
$icon = $pathPrefix . '../graphics/logo136.png';
|
||||||
|
if (!$isSelfService) {
|
||||||
|
$domain = $_SESSION['config']->getTwoFactorAuthenticationDomain();
|
||||||
|
}
|
||||||
return new PublicKeyCredentialRpEntity(
|
return new PublicKeyCredentialRpEntity(
|
||||||
'LDAP Account Manager', //Name
|
'LDAP Account Manager', //Name
|
||||||
null, // TODO check if domain is required
|
$domain,
|
||||||
null // TODO icon
|
$icon
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -473,21 +473,22 @@ if (extension_loaded('curl')) {
|
||||||
$twoFactorSelect = new htmlResponsiveSelect('twoFactor', $twoFactorOptions, array($conf->getTwoFactorAuthentication()), _('Provider'), '514');
|
$twoFactorSelect = new htmlResponsiveSelect('twoFactor', $twoFactorOptions, array($conf->getTwoFactorAuthentication()), _('Provider'), '514');
|
||||||
$twoFactorSelect->setHasDescriptiveElements(true);
|
$twoFactorSelect->setHasDescriptiveElements(true);
|
||||||
$twoFactorSelect->setTableRowsToHide(array(
|
$twoFactorSelect->setTableRowsToHide(array(
|
||||||
TwoFactorProviderService::TWO_FACTOR_NONE => array('twoFactorURL', 'twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel',
|
TwoFactorProviderService::TWO_FACTOR_NONE => array('twoFactorURL', 'twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel',
|
||||||
'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'),
|
'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute', 'twoFactorDomain'),
|
||||||
TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURLs', 'twoFactorClientId', 'twoFactorSecretKey'),
|
TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURLs', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorDomain'),
|
||||||
TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURL', 'twoFactorAttribute'),
|
TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURL', 'twoFactorAttribute', 'twoFactorDomain'),
|
||||||
TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURLs', 'twoFactorOptional', 'twoFactorInsecure', 'twoFactorLabel'),
|
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'),
|
'twoFactorOptional', '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',
|
||||||
'twoFactorOptional', 'twoFactorCaption', 'twoFactorAttribute'),
|
'twoFactorOptional', 'twoFactorCaption', 'twoFactorAttribute'),
|
||||||
TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel',
|
TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel',
|
||||||
'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')
|
||||||
));
|
));
|
||||||
$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');
|
||||||
|
@ -500,8 +501,10 @@ if (extension_loaded('curl')) {
|
||||||
$row->add($twoFactorUrl, 12);
|
$row->add($twoFactorUrl, 12);
|
||||||
$twoFactorClientId = new htmlResponsiveInputField(_("Client id"), 'twoFactorClientId', $conf->getTwoFactorAuthenticationClientId(), '524');
|
$twoFactorClientId = new htmlResponsiveInputField(_("Client id"), 'twoFactorClientId', $conf->getTwoFactorAuthenticationClientId(), '524');
|
||||||
$row->add($twoFactorClientId, 12);
|
$row->add($twoFactorClientId, 12);
|
||||||
$twoFactorSecretKey = new htmlResponsiveInputField(_("Secret key"), 'twoFactorSecretKey', $conf->getTwoFactorAuthenticationSecretKey(), '525');
|
$twoFactorSecretKey = new htmlResponsiveInputField(_("Secret key"), 'twoFactorSecretKey', $conf->getTwoFactorAuthenticationSecretKey(), '528');
|
||||||
$row->add($twoFactorSecretKey, 12);
|
$row->add($twoFactorSecretKey, 12);
|
||||||
|
$twoFactorDomain = new htmlResponsiveInputField(_("Domain"), 'twoFactorDomain', $conf->getTwoFactorAuthenticationDomain(), '529');
|
||||||
|
$row->add($twoFactorDomain, 12);
|
||||||
$twoFactorLabel = new htmlResponsiveInputField(_("Label"), 'twoFactorLabel', $conf->getTwoFactorAuthenticationLabel(), '517');
|
$twoFactorLabel = new htmlResponsiveInputField(_("Label"), 'twoFactorLabel', $conf->getTwoFactorAuthenticationLabel(), '517');
|
||||||
$row->add($twoFactorLabel, 12);
|
$row->add($twoFactorLabel, 12);
|
||||||
$row->add(new htmlResponsiveInputCheckbox('twoFactorOptional', $conf->getTwoFactorAuthenticationOptional(), _('Optional'), '519'), 12);
|
$row->add(new htmlResponsiveInputCheckbox('twoFactorOptional', $conf->getTwoFactorAuthenticationOptional(), _('Optional'), '519'), 12);
|
||||||
|
@ -741,6 +744,7 @@ function checkInput() {
|
||||||
}
|
}
|
||||||
$conf->setTwoFactorAuthenticationClientId($_POST['twoFactorClientId']);
|
$conf->setTwoFactorAuthenticationClientId($_POST['twoFactorClientId']);
|
||||||
$conf->setTwoFactorAuthenticationSecretKey($_POST['twoFactorSecretKey']);
|
$conf->setTwoFactorAuthenticationSecretKey($_POST['twoFactorSecretKey']);
|
||||||
|
$conf->setTwoFactorAuthenticationDomain($_POST['twoFactorDomain']);
|
||||||
$conf->setTwoFactorAuthenticationInsecure(isset($_POST['twoFactorInsecure']) && ($_POST['twoFactorInsecure'] == 'on'));
|
$conf->setTwoFactorAuthenticationInsecure(isset($_POST['twoFactorInsecure']) && ($_POST['twoFactorInsecure'] == 'on'));
|
||||||
$conf->setTwoFactorAuthenticationLabel($_POST['twoFactorLabel']);
|
$conf->setTwoFactorAuthenticationLabel($_POST['twoFactorLabel']);
|
||||||
$conf->setTwoFactorAuthenticationOptional(isset($_POST['twoFactorOptional']) && ($_POST['twoFactorOptional'] == 'on'));
|
$conf->setTwoFactorAuthenticationOptional(isset($_POST['twoFactorOptional']) && ($_POST['twoFactorOptional'] == 'on'));
|
||||||
|
|
|
@ -1411,19 +1411,17 @@ window.lam.webauthn.run = function(prefix) {
|
||||||
* @param publicKey registration object
|
* @param publicKey registration object
|
||||||
*/
|
*/
|
||||||
window.lam.webauthn.register = function(publicKey) {
|
window.lam.webauthn.register = function(publicKey) {
|
||||||
console.log(publicKey);
|
|
||||||
publicKey.challenge = Uint8Array.from(window.atob(publicKey.challenge), c=>c.charCodeAt(0));
|
publicKey.challenge = Uint8Array.from(window.atob(publicKey.challenge), c=>c.charCodeAt(0));
|
||||||
publicKey.user.id = Uint8Array.from(window.atob(publicKey.user.id), c=>c.charCodeAt(0));
|
publicKey.user.id = Uint8Array.from(window.atob(publicKey.user.id), c=>c.charCodeAt(0));
|
||||||
navigator.credentials.create({publicKey})
|
navigator.credentials.create({publicKey})
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
console.log(data);
|
|
||||||
let publicKeyCredential = {
|
let publicKeyCredential = {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
type: data.type,
|
type: data.type,
|
||||||
rawId: btoa(String.fromCharCode(new Uint8Array(data.rawId))),
|
rawId: btoa(String.fromCharCode(new Uint8Array(data.rawId))),
|
||||||
response: {
|
response: {
|
||||||
clientDataJSON: btoa(String.fromCharCode((new Uint8Array(data.response.clientDataJSON)))),
|
clientDataJSON: window.lam.webauthn.arrayToBase64String(new Uint8Array(data.response.clientDataJSON)),
|
||||||
attestationObject: btoa(String.fromCharCode((new Uint8Array(data.response.attestationObject))))
|
attestationObject: window.lam.webauthn.arrayToBase64String(new Uint8Array(data.response.attestationObject))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
console.log(publicKeyCredential);
|
console.log(publicKeyCredential);
|
||||||
|
@ -1433,6 +1431,16 @@ window.lam.webauthn.register = function(publicKey) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an array to a base64 string.
|
||||||
|
*
|
||||||
|
* @param input array
|
||||||
|
* @returns base64 string
|
||||||
|
*/
|
||||||
|
window.lam.webauthn.arrayToBase64String = function(input) {
|
||||||
|
return btoa(String.fromCharCode(...input));
|
||||||
|
}
|
||||||
|
|
||||||
jQuery(document).ready(function() {
|
jQuery(document).ready(function() {
|
||||||
window.lam.gui.equalHeight();
|
window.lam.gui.equalHeight();
|
||||||
window.lam.form.autoTrim();
|
window.lam.form.autoTrim();
|
||||||
|
|
|
@ -196,7 +196,7 @@ class Ajax {
|
||||||
$userDN = $_SESSION['ldap']->getUserName();
|
$userDN = $_SESSION['ldap']->getUserName();
|
||||||
$isRegistered = isRegistered($userDN);
|
$isRegistered = isRegistered($userDN);
|
||||||
if (!$isRegistered) {
|
if (!$isRegistered) {
|
||||||
$registrationObject = getRegistrationObject($userDN);
|
$registrationObject = getRegistrationObject($userDN, $isSelfService);
|
||||||
echo json_encode(
|
echo json_encode(
|
||||||
array(
|
array(
|
||||||
'action' => 'register',
|
'action' => 'register',
|
||||||
|
|
|
@ -565,6 +565,17 @@ class LAMConfigTest extends PHPUnit_Framework_TestCase {
|
||||||
$this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationSecretKey());
|
$this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationSecretKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests LAMConfig->getTwoFactorAuthenticationDomain() and LAMConfig->setTwoFactorAuthenticationDomain()
|
||||||
|
*/
|
||||||
|
public function testTwoFactorAuthenticationDomain() {
|
||||||
|
$val = 'test.com';
|
||||||
|
$this->lAMConfig->setTwoFactorAuthenticationDomain($val);
|
||||||
|
$this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationDomain());
|
||||||
|
$this->doSave();
|
||||||
|
$this->assertEquals($val, $this->lAMConfig->getTwoFactorAuthenticationDomain());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests LAMConfig->getTwoFactorAuthenticationInsecure() and LAMConfig->setTwoFactorAuthenticationInsecure()
|
* Tests LAMConfig->getTwoFactorAuthenticationInsecure() and LAMConfig->setTwoFactorAuthenticationInsecure()
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue