mirror of
https://git.code.sf.net/p/seeddms/code
synced 2025-11-28 18:40:39 +00:00
no longer needed, because webauthn has moved into extension
This commit is contained in:
parent
f85ceca4ca
commit
6d440e0939
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Setup webauthn authentication
|
||||
*
|
||||
* @category DMS
|
||||
* @package SeedDMS
|
||||
* @license GPL 2
|
||||
* @version @version@
|
||||
* @author Uwe Steinmann <uwe@steinmann.cx>
|
||||
* @copyright Copyright (C) 2016 Uwe Steinmann
|
||||
* @version Release: @package_version@
|
||||
*/
|
||||
|
||||
if(!isset($settings))
|
||||
require_once("../inc/inc.Settings.php");
|
||||
require_once("inc/inc.Utils.php");
|
||||
require_once("inc/inc.LogInit.php");
|
||||
require_once("inc/inc.Language.php");
|
||||
require_once("inc/inc.Init.php");
|
||||
require_once("inc/inc.Extension.php");
|
||||
require_once("inc/inc.DBInit.php");
|
||||
require_once("inc/inc.ClassUI.php");
|
||||
require_once("inc/inc.WebAuthn.php");
|
||||
require_once("inc/inc.Authentication.php");
|
||||
|
||||
$tmp = explode('.', basename($_SERVER['SCRIPT_FILENAME']));
|
||||
$view = UI::factory($theme, $tmp[1], array('dms'=>$dms, 'user'=>$user));
|
||||
$accessop = new SeedDMS_AccessOperation($dms, $user, $settings);
|
||||
|
||||
if ($user->isGuest()) {
|
||||
UI::exitError(getMLText("webauthn"),getMLText("access_denied"));
|
||||
}
|
||||
|
||||
if($view) {
|
||||
$view->setParam('sitename', $settings->_siteName);
|
||||
$view->setParam('enable2factauth', $settings->_enable2FactorAuthentication);
|
||||
$view->setParam('accessobject', $accessop);
|
||||
$view($_REQUEST);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
|
@ -1,425 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Implementation of SetupWebauthn view
|
||||
*
|
||||
* @category DMS
|
||||
* @package SeedDMS
|
||||
* @license GPL 2
|
||||
* @version @version@
|
||||
* @author Uwe Steinmann <uwe@steinmann.cx>
|
||||
* @copyright Copyright (C) 2016 Uwe Steinmann
|
||||
* @version Release: @package_version@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Include parent class
|
||||
*/
|
||||
//require_once("class.Bootstrap.php");
|
||||
|
||||
/**
|
||||
* Include classes for 2-factor authentication
|
||||
*/
|
||||
require "vendor/autoload.php";
|
||||
|
||||
/**
|
||||
* Class which outputs the html page for ForcePasswordChange view
|
||||
*
|
||||
* @category DMS
|
||||
* @package SeedDMS
|
||||
* @author Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
|
||||
* @copyright Copyright (C) 2016 Uwe Steinmann
|
||||
* @version Release: @package_version@
|
||||
*/
|
||||
class SeedDMS_View_SetupWebauthn extends SeedDMS_Bootstrap_Style {
|
||||
|
||||
function css() { /* {{{ */
|
||||
header('Content-Type: text/css; charset=UTF-8');
|
||||
?>
|
||||
.cdokey {
|
||||
display: none;
|
||||
background-color: orange;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
}
|
||||
<?php
|
||||
} /* }}} */
|
||||
|
||||
function js() { /* {{{ */
|
||||
header('Content-Type: application/javascript');
|
||||
?>
|
||||
function webauthnRegister(key, callback){
|
||||
key = JSON.parse(key);
|
||||
key.publicKey.attestation = undefined;
|
||||
key.publicKey.challenge = new Uint8Array(key.publicKey.challenge); // convert type for use by key
|
||||
key.publicKey.user.id = new Uint8Array(key.publicKey.user.id);
|
||||
|
||||
//console.log(key);
|
||||
navigator.credentials.create({publicKey: key.publicKey})
|
||||
.then(function (aNewCredentialInfo) {
|
||||
console.log("Credentials.Create response: ", aNewCredentialInfo);
|
||||
var cd = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(aNewCredentialInfo.response.clientDataJSON)));
|
||||
if (key.b64challenge != cd.challenge) {
|
||||
return callback(false, 'key returned something unexpected (1)');
|
||||
}
|
||||
if ('https://'+key.publicKey.rp.name != cd.origin) {
|
||||
console.log(key.publicKey.rp.name);
|
||||
console.log(cd.origin);
|
||||
return callback(false, 'key returned something unexpected (2)');
|
||||
}
|
||||
if (! ('type' in cd)) {
|
||||
return callback(false, 'key returned something unexpected (3)');
|
||||
}
|
||||
if (cd.type != 'webauthn.create') {
|
||||
return callback(false, 'key returned something unexpected (4)');
|
||||
}
|
||||
|
||||
var ao = [];
|
||||
(new Uint8Array(aNewCredentialInfo.response.attestationObject)).forEach(function(v){
|
||||
ao.push(v);
|
||||
});
|
||||
var rawId = [];
|
||||
(new Uint8Array(aNewCredentialInfo.rawId)).forEach(function(v){
|
||||
rawId.push(v);
|
||||
});
|
||||
var info = {
|
||||
rawId: rawId,
|
||||
id: aNewCredentialInfo.id,
|
||||
type: aNewCredentialInfo.type,
|
||||
response: {
|
||||
attestationObject: ao,
|
||||
clientDataJSON:
|
||||
JSON.parse(String.fromCharCode.apply(null, new Uint8Array(aNewCredentialInfo.response.clientDataJSON)))
|
||||
}
|
||||
};
|
||||
console.log("Info: ", info);
|
||||
callback(true, JSON.stringify(info));
|
||||
})
|
||||
.catch(function (aErr) {
|
||||
if (
|
||||
("name" in aErr) && (aErr.name == "AbortError" || aErr.name == "NS_ERROR_ABORT")
|
||||
|| aErr.name == 'NotAllowedError'
|
||||
) {
|
||||
callback(false, 'abort');
|
||||
} else {
|
||||
callback(false, aErr.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
function webauthnAuthenticate(key, cb){
|
||||
var pk = JSON.parse(key);
|
||||
var originalChallenge = pk.challenge;
|
||||
pk.challenge = new Uint8Array(pk.challenge);
|
||||
pk.allowCredentials.forEach(function(k, idx){
|
||||
pk.allowCredentials[idx].id = new Uint8Array(k.id);
|
||||
});
|
||||
/* ask the browser to prompt the user */
|
||||
navigator.credentials.get({publicKey: pk})
|
||||
.then(function(aAssertion) {
|
||||
// console.log("Credentials.Get response: ", aAssertion);
|
||||
var ida = [];
|
||||
(new Uint8Array(aAssertion.rawId)).forEach(function(v){ ida.push(v); });
|
||||
var cd = JSON.parse(String.fromCharCode.apply(null,
|
||||
new Uint8Array(aAssertion.response.clientDataJSON)));
|
||||
var cda = [];
|
||||
(new Uint8Array(aAssertion.response.clientDataJSON)).forEach(function(v){ cda.push(v); });
|
||||
var ad = [];
|
||||
(new Uint8Array(aAssertion.response.authenticatorData)).forEach(function(v){ ad.push(v); });
|
||||
var sig = [];
|
||||
(new Uint8Array(aAssertion.response.signature)).forEach(function(v){ sig.push(v); });
|
||||
var info = {
|
||||
type: aAssertion.type,
|
||||
originalChallenge: originalChallenge,
|
||||
rawId: ida,
|
||||
response: {
|
||||
authenticatorData: ad,
|
||||
clientData: cd,
|
||||
clientDataJSONarray: cda,
|
||||
signature: sig
|
||||
}
|
||||
};
|
||||
cb(true, JSON.stringify(info));
|
||||
})
|
||||
.catch(function (aErr) {
|
||||
if (("name" in aErr) && (aErr.name == "AbortError" || aErr.name == "NS_ERROR_ABORT" ||
|
||||
aErr.name == "NotAllowedError")) {
|
||||
cb(false, 'abort');
|
||||
} else {
|
||||
cb(false, aErr.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(function(){
|
||||
|
||||
$('#iregisterform').submit(function(ev){
|
||||
var self = $(this);
|
||||
ev.preventDefault();
|
||||
var cp = $('select[name=cp]').val();
|
||||
if (cp == "") {
|
||||
$('.cerror').show().text("Please choose cross-platform setting - see note below about what this means");
|
||||
return;
|
||||
}
|
||||
|
||||
$('.cerror').empty().hide();
|
||||
|
||||
$.ajax({url: '../out/out.SetupWebauthn.php',
|
||||
method: 'POST',
|
||||
data: {action: 'registeruser', registerusername: self.find('[name=registerusername]').val(), crossplatform: cp},
|
||||
dataType: 'json',
|
||||
success: function(j){
|
||||
/* activate the key and get the response */
|
||||
webauthnRegister(j.challenge, function(success, info){
|
||||
if (success) {
|
||||
$.ajax({url: '../out/out.SetupWebauthn.php',
|
||||
method: 'POST',
|
||||
data: {action: 'register', register: info},
|
||||
dataType: 'json',
|
||||
success: function(j){
|
||||
noty({
|
||||
text: 'registration completed successfully',
|
||||
type: 'success',
|
||||
dismissQueue: true,
|
||||
layout: 'topRight',
|
||||
theme: 'defaultTheme',
|
||||
timeout: 1500,
|
||||
});
|
||||
},
|
||||
error: function(xhr, status, error){
|
||||
noty({
|
||||
text: 'registration failed: '+error+": "+xhr.responseText,
|
||||
type: 'error',
|
||||
dismissQueue: true,
|
||||
layout: 'topRight',
|
||||
theme: 'defaultTheme',
|
||||
timeout: 1500,
|
||||
});
|
||||
// $('.cerror').text("registration failed: "+error+": "+xhr.responseText).show();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
noty({
|
||||
text: info,
|
||||
type: 'error',
|
||||
dismissQueue: true,
|
||||
layout: 'topRight',
|
||||
theme: 'defaultTheme',
|
||||
timeout: 1500,
|
||||
});
|
||||
// $('.cerror').text(info).show();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
error: function(xhr, status, error){
|
||||
noty({
|
||||
text: "couldn't initiate registration: "+error+": "+xhr.responseText,
|
||||
type: 'error',
|
||||
dismissQueue: true,
|
||||
layout: 'topRight',
|
||||
theme: 'defaultTheme',
|
||||
timeout: 1500,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#iloginform').submit(function(ev){
|
||||
var self = $(this);
|
||||
ev.preventDefault();
|
||||
$('.cerror').empty().hide();
|
||||
|
||||
$.ajax({url: '../out/out.SetupWebauthn.php',
|
||||
method: 'POST',
|
||||
data: {action: 'preparelogin', loginusername: self.find('[name=loginusername]').val()},
|
||||
dataType: 'json',
|
||||
success: function(j){
|
||||
/* activate the key and get the response */
|
||||
webauthnAuthenticate(j.challenge, function(success, info){
|
||||
if (success) {
|
||||
$.ajax({url: '../out/out.SetupWebauthn.php',
|
||||
method: 'POST',
|
||||
data: {action: 'login', login: info},
|
||||
dataType: 'json',
|
||||
success: function(j){
|
||||
noty({
|
||||
text: 'login completed successfully',
|
||||
type: 'success',
|
||||
dismissQueue: true,
|
||||
layout: 'topRight',
|
||||
theme: 'defaultTheme',
|
||||
timeout: 1500,
|
||||
});
|
||||
},
|
||||
error: function(xhr, status, error){
|
||||
noty({
|
||||
text: 'login failed: '+error+": "+xhr.responseText,
|
||||
type: 'error',
|
||||
dismissQueue: true,
|
||||
layout: 'topRight',
|
||||
theme: 'defaultTheme',
|
||||
timeout: 1500,
|
||||
});
|
||||
// $('.cerror').text("login failed: "+error+": "+xhr.responseText).show();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
noty({
|
||||
text: info,
|
||||
type: 'error',
|
||||
dismissQueue: true,
|
||||
layout: 'topRight',
|
||||
theme: 'defaultTheme',
|
||||
timeout: 1500,
|
||||
});
|
||||
// $('.cerror').text(info).show();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
error: function(xhr, status, error){
|
||||
noty({
|
||||
text: "couldn't initiate login: "+error+": "+xhr.responseText,
|
||||
type: 'error',
|
||||
dismissQueue: true,
|
||||
layout: 'topRight',
|
||||
theme: 'defaultTheme',
|
||||
timeout: 1500,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
<?php
|
||||
} /* }}} */
|
||||
|
||||
function registeruser() { /* {{{ */
|
||||
$dms = $this->params['dms'];
|
||||
$user = $this->params['user'];
|
||||
|
||||
$webauthn = new \Davidearl\WebAuthn\WebAuthn($_SERVER['HTTP_HOST']);
|
||||
|
||||
/* initiate the registration */
|
||||
$username = $user->getLogin();
|
||||
$userid = $user->getId();
|
||||
$crossplatform = ! empty($_POST['crossplatform']) && $_POST['crossplatform'] == 'Yes';
|
||||
|
||||
// $user->setWebauthn($webauthn->cancel());
|
||||
|
||||
$j = ['challenge' => $webauthn->prepareChallengeForRegistration($username, $userid, $crossplatform)];
|
||||
header('Content-type: application/json');
|
||||
echo json_encode($j);
|
||||
} /* }}} */
|
||||
|
||||
function register() { /* {{{ */
|
||||
$dms = $this->params['dms'];
|
||||
$user = $this->params['user'];
|
||||
|
||||
$webauthn = new \Davidearl\WebAuthn\WebAuthn($_SERVER['HTTP_HOST']);
|
||||
|
||||
/* The heart of the matter */
|
||||
$user->setWebauthn($webauthn->register($_POST['register'], $user->getWebauthn()));
|
||||
|
||||
$j = 'ok';
|
||||
|
||||
header('Content-type: application/json');
|
||||
echo json_encode($j);
|
||||
} /* }}} */
|
||||
|
||||
/**
|
||||
* Return challange for login process
|
||||
*
|
||||
* This method is quite similar to the one in controllers/class.Login.php
|
||||
*/
|
||||
function preparelogin() { /* {{{ */
|
||||
$dms = $this->params['dms'];
|
||||
$user = $this->params['user'];
|
||||
|
||||
$webauthn = new \Davidearl\WebAuthn\WebAuthn($_SERVER['HTTP_HOST']);
|
||||
|
||||
$j['challenge'] = $webauthn->prepareForLogin($user->getWebauthn());
|
||||
header('Content-type: application/json');
|
||||
echo json_encode($j);
|
||||
} /* }}} */
|
||||
|
||||
/**
|
||||
* Do a fake login to check if authentication works
|
||||
*
|
||||
* This method is quite similar to the one in controllers/class.Login.php
|
||||
*/
|
||||
function login() { /* {{{ */
|
||||
$dms = $this->params['dms'];
|
||||
$user = $this->params['user'];
|
||||
|
||||
$webauthn = new \Davidearl\WebAuthn\WebAuthn($_SERVER['HTTP_HOST']);
|
||||
|
||||
if (! $webauthn->authenticate($_POST['login'], $user->getWebauthn())) {
|
||||
http_response_code(401);
|
||||
echo 'failed to authenticate with that key';
|
||||
exit;
|
||||
}
|
||||
$j = 'ok';
|
||||
header('Content-type: application/json');
|
||||
echo json_encode($j);
|
||||
} /* }}} */
|
||||
|
||||
function show() { /* {{{ */
|
||||
$dms = $this->params['dms'];
|
||||
$user = $this->params['user'];
|
||||
$sitename = $this->params['sitename'];
|
||||
|
||||
$this->htmlStartPage(getMLText("webauthn"), "forcepasswordchange");
|
||||
$this->globalNavigation();
|
||||
$this->contentStart();
|
||||
$this->pageNavigation(getMLText("my_account"), "my_account");
|
||||
$this->contentHeading(getMLText('webauthn_auth'));
|
||||
echo "<div class=\"alert\">".getMLText('webauthn_info')."</div>";
|
||||
echo '<div class="row-fluid">';
|
||||
echo '<div class="span6">';
|
||||
$this->contentHeading(getMLText('webauthn_registration'));
|
||||
$this->contentContainerStart();
|
||||
?>
|
||||
<div class='cerror'></div>
|
||||
<div class='cdone'></div>
|
||||
|
||||
<div class='ccontent'></div>
|
||||
<form class="-form-horizontal" id="iregisterform" action="/" method="post" name="form1">
|
||||
<input type="hidden" name="registerusername" value="<?= $user->getLogin() ?>" />
|
||||
<!-- div class="control-group"><label class="control-label"><?php printMLText('webauth_crossplatform'); ?></label><div class="controls" -->
|
||||
<select class="chzn-select" name="crossplatform" id="crossplatform">
|
||||
<option value="yes"><?= getMLText('webauth_crossplatform') ?></option>
|
||||
<option value="no">No</option>
|
||||
</select>
|
||||
<!-- /div></div -->
|
||||
<?php
|
||||
$this->formSubmit(getMLText('submit_webauthn_register'));
|
||||
?>
|
||||
</form>
|
||||
<?php
|
||||
$this->contentContainerEnd();
|
||||
|
||||
echo $this->infoMsg(getMLText('webauthn_crossplatform_info'));
|
||||
echo "</div>";
|
||||
if($user->getWebauthn()) {
|
||||
echo '<div class="span6">';
|
||||
$this->contentHeading(getMLText('webauthn_login_test'));
|
||||
$this->contentContainerStart();
|
||||
?>
|
||||
<form class="form-horizontal" id="iloginform" action="/" method="post" name="form1">
|
||||
<input type="hidden" name="loginusername" value="<?= $user->getLogin() ?>" />
|
||||
<?php
|
||||
$this->formSubmit(getMLText('submit_webauthn_login'));
|
||||
?>
|
||||
</form>
|
||||
<?php
|
||||
$this->contentContainerEnd();
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
$this->contentEnd();
|
||||
$this->htmlEndPage();
|
||||
} /* }}} */
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user