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.')), | ||||
| 				"528" => array ("Headline" => _('User name attribute'), | ||||
| 					"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"), | ||||
| 					"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"), | ||||
|  |  | |||
|  | @ -607,6 +607,7 @@ class LAMConfig { | |||
| 	private $twoFactorAuthenticationURL = 'https://localhost'; | ||||
| 	private $twoFactorAuthenticationClientId = null; | ||||
| 	private $twoFactorAuthenticationSecretKey = null; | ||||
| 	private $twoFactorAuthenticationDomain = null; | ||||
| 	private $twoFactorAuthenticationInsecure = false; | ||||
| 	private $twoFactorAuthenticationLabel = null; | ||||
| 	private $twoFactorAuthenticationOptional = false; | ||||
|  | @ -625,7 +626,7 @@ class LAMConfig { | |||
| 		'scriptUserName', 'scriptSSHKey', 'scriptSSHKeyPassword', 'twoFactorAuthentication', 'twoFactorAuthenticationURL', | ||||
| 		'twoFactorAuthenticationInsecure', 'twoFactorAuthenticationLabel', 'twoFactorAuthenticationOptional', | ||||
| 		'twoFactorAuthenticationCaption', 'twoFactorAuthenticationClientId', 'twoFactorAuthenticationSecretKey', | ||||
| 		'twoFactorAuthenticationAttribute', 'referentialIntegrityOverlay' | ||||
| 		'twoFactorAuthenticationDomain', 'twoFactorAuthenticationAttribute', 'referentialIntegrityOverlay' | ||||
| 	); | ||||
| 
 | ||||
| 
 | ||||
|  | @ -991,6 +992,9 @@ class LAMConfig { | |||
| 			if (!in_array("twoFactorAuthenticationSecretKey", $saved)) { | ||||
| 				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)) { | ||||
| 				array_push($file_array, "\n" . "twoFactorAuthenticationInsecure: " . $this->twoFactorAuthenticationInsecure . "\n"); | ||||
| 			} | ||||
|  | @ -2416,6 +2420,24 @@ class LAMConfig { | |||
| 		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. | ||||
| 	 * | ||||
|  |  | |||
|  | @ -51,10 +51,11 @@ function isRegistered($dn) { | |||
|  * Returns a challenge for a new token. | ||||
|  * | ||||
|  * @param string $dn DN | ||||
|  * @param bool $isSelfService is executed in self service | ||||
|  * @return PublicKeyCredentialCreationOptions challenge | ||||
|  */ | ||||
| function getRegistrationObject($dn) { | ||||
| 	$rpEntity = createRpEntry(); | ||||
| function getRegistrationObject($dn, $isSelfService) { | ||||
| 	$rpEntity = createRpEntry($isSelfService); | ||||
| 	$userEntity = getUserEntity($dn); | ||||
| 	$challenge = generateRandomPassword(32); | ||||
| 	$credentialParameters = getCredentialParameters(); | ||||
|  | @ -76,13 +77,19 @@ function getRegistrationObject($dn) { | |||
| /** | ||||
|  * Returns the part that identifies the server and application. | ||||
|  * | ||||
|  * @param bool $isSelfService is executed in self service | ||||
|  * @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( | ||||
| 		'LDAP Account Manager', //Name
 | ||||
| 		null, // TODO check if domain is required
 | ||||
| 		null // TODO icon
 | ||||
| 		$domain, | ||||
| 		$icon | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -473,21 +473,22 @@ if (extension_loaded('curl')) { | |||
| 	$twoFactorSelect = new htmlResponsiveSelect('twoFactor', $twoFactorOptions, array($conf->getTwoFactorAuthentication()), _('Provider'), '514'); | ||||
| 	$twoFactorSelect->setHasDescriptiveElements(true); | ||||
| 	$twoFactorSelect->setTableRowsToHide(array( | ||||
| 			TwoFactorProviderService::TWO_FACTOR_NONE => array('twoFactorURL', 'twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel', | ||||
| 				'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'), | ||||
| 			TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURLs', 'twoFactorClientId', 'twoFactorSecretKey'), | ||||
| 			TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURL', 'twoFactorAttribute'), | ||||
| 			TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURLs', 'twoFactorOptional', 'twoFactorInsecure', 'twoFactorLabel'), | ||||
| 			TwoFactorProviderService::TWO_FACTOR_WEBAUTHN => array('twoFactorURL', 'twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel', | ||||
| 				'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'), | ||||
| 		TwoFactorProviderService::TWO_FACTOR_NONE => array('twoFactorURL', 'twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel', | ||||
| 			'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute', 'twoFactorDomain'), | ||||
| 		TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURLs', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorDomain'), | ||||
| 		TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURL', 'twoFactorAttribute', 'twoFactorDomain'), | ||||
| 		TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURLs', 'twoFactorOptional', 'twoFactorInsecure', 'twoFactorLabel', 'twoFactorDomain'), | ||||
| 		TwoFactorProviderService::TWO_FACTOR_WEBAUTHN => array('twoFactorURL', 'twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel', | ||||
| 			'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'), | ||||
| 	)); | ||||
| 	$twoFactorSelect->setTableRowsToShow(array( | ||||
| 			TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', | ||||
| 				'twoFactorOptional', 'twoFactorCaption', 'twoFactorAttribute'), | ||||
| 			TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel', | ||||
| 				'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey'), | ||||
| 			TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURL', 'twoFactorLabel', | ||||
| 				'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'), | ||||
| 		TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA => array('twoFactorURL', 'twoFactorInsecure', 'twoFactorLabel', | ||||
| 			'twoFactorOptional', 'twoFactorCaption', 'twoFactorAttribute'), | ||||
| 		TwoFactorProviderService::TWO_FACTOR_YUBICO => array('twoFactorURLs', 'twoFactorInsecure', 'twoFactorLabel', | ||||
| 			'twoFactorOptional', 'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey'), | ||||
| 		TwoFactorProviderService::TWO_FACTOR_DUO => array('twoFactorURL', 'twoFactorLabel', | ||||
| 			'twoFactorCaption', 'twoFactorClientId', 'twoFactorSecretKey', 'twoFactorAttribute'), | ||||
| 		TwoFactorProviderService::TWO_FACTOR_WEBAUTHN => array('twoFactorDomain') | ||||
| 	)); | ||||
| 	$row->add($twoFactorSelect, 12); | ||||
| 	$twoFactorAttribute = new htmlResponsiveInputField(_("User name attribute"), 'twoFactorAttribute', $conf->getTwoFactorAuthenticationAttribute(), '528'); | ||||
|  | @ -500,8 +501,10 @@ if (extension_loaded('curl')) { | |||
| 	$row->add($twoFactorUrl, 12); | ||||
| 	$twoFactorClientId = new htmlResponsiveInputField(_("Client id"), 'twoFactorClientId', $conf->getTwoFactorAuthenticationClientId(), '524'); | ||||
| 	$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); | ||||
| 	$twoFactorDomain = new htmlResponsiveInputField(_("Domain"), 'twoFactorDomain', $conf->getTwoFactorAuthenticationDomain(), '529'); | ||||
| 	$row->add($twoFactorDomain, 12); | ||||
| 	$twoFactorLabel = new htmlResponsiveInputField(_("Label"), 'twoFactorLabel', $conf->getTwoFactorAuthenticationLabel(), '517'); | ||||
| 	$row->add($twoFactorLabel, 12); | ||||
| 	$row->add(new htmlResponsiveInputCheckbox('twoFactorOptional', $conf->getTwoFactorAuthenticationOptional(), _('Optional'), '519'), 12); | ||||
|  | @ -741,6 +744,7 @@ function checkInput() { | |||
| 		} | ||||
| 		$conf->setTwoFactorAuthenticationClientId($_POST['twoFactorClientId']); | ||||
| 		$conf->setTwoFactorAuthenticationSecretKey($_POST['twoFactorSecretKey']); | ||||
| 		$conf->setTwoFactorAuthenticationDomain($_POST['twoFactorDomain']); | ||||
| 		$conf->setTwoFactorAuthenticationInsecure(isset($_POST['twoFactorInsecure']) && ($_POST['twoFactorInsecure'] == 'on')); | ||||
| 		$conf->setTwoFactorAuthenticationLabel($_POST['twoFactorLabel']); | ||||
| 		$conf->setTwoFactorAuthenticationOptional(isset($_POST['twoFactorOptional']) && ($_POST['twoFactorOptional'] == 'on')); | ||||
|  |  | |||
|  | @ -1411,19 +1411,17 @@ window.lam.webauthn.run = function(prefix) { | |||
|  * @param publicKey registration object | ||||
|  */ | ||||
| window.lam.webauthn.register = function(publicKey) { | ||||
| 	console.log(publicKey); | ||||
| 	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)); | ||||
| 	navigator.credentials.create({publicKey}) | ||||
| 		.then(function (data) { | ||||
| 			console.log(data); | ||||
| 			let publicKeyCredential = { | ||||
| 				id: data.id, | ||||
| 				type: data.type, | ||||
| 				rawId: btoa(String.fromCharCode(new Uint8Array(data.rawId))), | ||||
| 				response: { | ||||
| 					clientDataJSON: btoa(String.fromCharCode((new Uint8Array(data.response.clientDataJSON)))), | ||||
| 					attestationObject: btoa(String.fromCharCode((new Uint8Array(data.response.attestationObject)))) | ||||
| 					clientDataJSON: window.lam.webauthn.arrayToBase64String(new Uint8Array(data.response.clientDataJSON)), | ||||
| 					attestationObject: window.lam.webauthn.arrayToBase64String(new Uint8Array(data.response.attestationObject)) | ||||
| 				} | ||||
| 			}; | ||||
| 			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() { | ||||
| 	window.lam.gui.equalHeight(); | ||||
| 	window.lam.form.autoTrim(); | ||||
|  |  | |||
|  | @ -196,7 +196,7 @@ class Ajax { | |||
| 		$userDN = $_SESSION['ldap']->getUserName(); | ||||
| 		$isRegistered = isRegistered($userDN); | ||||
| 		if (!$isRegistered) { | ||||
| 			$registrationObject = getRegistrationObject($userDN); | ||||
| 			$registrationObject = getRegistrationObject($userDN, $isSelfService); | ||||
| 			echo json_encode( | ||||
| 				array( | ||||
| 					'action' => 'register', | ||||
|  |  | |||
|  | @ -565,6 +565,17 @@ class LAMConfigTest extends PHPUnit_Framework_TestCase { | |||
| 		$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() | ||||
| 	 */ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue