Added TwoFactor Authentication (RFC4226)

Tested against Google-Authenticator app on Android 4.4.4

Made `verify_hotp` more efficient.

Added autofocus on twofactor input

Added GUI Unlock and Remove for TwoFactor credentials in /edituser/

Allow additional tries after elapsed time from last try exceeds configured parameter `$config['twofactor_lock']`.
If `$config['twofactor_lock']` is not defined or is set to `0`, administrators have to unlock accounts that exceed 3 failures via GUI.

Added Documentation

Moved TwoFactor form to logon.inc.php
Disabled autocomplete on twofactor input field
Updated Docs to include link to Google-Authenticator's install-guides

Moved authentication logic from authenticate.inc.php to twofactor.lib.php

typo in docblock for `twofactor_auth()`

Fixed scrutinizer bugs

To please scrutinizer
This commit is contained in:
f0o
2014-12-24 21:22:02 +00:00
parent 7dccc13a6c
commit d66cec7017
8 changed files with 472 additions and 5 deletions

View File

@@ -65,6 +65,108 @@ if (passwordscanchange($_SESSION['username']))
echo("</div>");
}
if( $config['twofactor'] === true ) {
if( $_POST['twofactorremove'] == 1 ) {
require_once($config['install_dir']."/html/includes/authentication/twofactor.lib.php");
if( !isset($_POST['twofactor']) ) {
echo '<div class="well"><form class="form-horizontal" role="form" action="" method="post" name="twofactorform">';
echo '<input type="hidden" name="twofactorremove" value="1" />';
echo twofactor_form(false);
echo '</form></div>';
} else{
$twofactor = dbFetchRow('SELECT twofactor FROM users WHERE username = ?', array($_SESSION['username']));
if( empty($twofactor['twofactor']) ) {
echo '<div class="alert alert-danger">Error: How did you even get here?!</div><script>window.location = "/preferences/";</script>';
} else {
$twofactor = json_decode($twofactor['twofactor'],true);
}
if( verify_hotp($twofactor['key'],$_POST['twofactor'],$twofactor['counter']) ) {
if( !dbUpdate(array('twofactor' => ''),'users','username = ?',array($_SESSION['username'])) ) {
echo '<div class="alert alert-danger">Error while disabling TwoFactor.</div>';
} else {
echo '<div class="alert alert-success">TwoFactor Disabled.</div>';
}
} else {
session_destroy();
echo '<div class="alert alert-danger">Error: Supplied TwoFactor Token is wrong, you\'ve been logged out.</div><script>window.location = "/";</script>';
}
}
} else {
$twofactor = dbFetchRow("SELECT twofactor FROM users WHERE username = ?", array($_SESSION['username']));
echo '<script src="/js/jquery.qrcode.min.js"></script>';
echo '<div class="well"><h3>Two-Factor Authentication</h3>';
if( !empty($twofactor['twofactor']) ) {
$twofactor = json_decode($twofactor['twofactor'],true);
$twofactor['text'] = "<div class='form-group'>
<label for='twofactorkey' class='col-sm-2 control-label'>Secret Key</label>
<div class='col-sm-4'>
<input type='text' name='twofactorkey' autocomplete='off' disabled class='form-control input-sm' value='".$twofactor['key']."' />
</div>
</div>";
if( $twofactor['counter'] !== false ) {
$twofactor['uri'] = "otpauth://hotp/".$_SESSION['username']."?issuer=LibreNMS&counter=".$twofactor['counter']."&secret=".$twofactor['key'];
$twofactor['text'] .= "<div class='form-group'>
<label for='twofactorcounter' class='col-sm-2 control-label'>Counter</label>
<div class='col-sm-4'>
<input type='text' name='twofactorcounter' autocomplete='off' disabled class='form-control input-sm' value='".$twofactor['counter']."' />
</div>
</div>";
} else {
$twofactor['uri'] = "otpauth://totp/".$_SESSION['username']."?issuer=LibreNMS&secret=".$twofactor['key'];
}
echo '<div id="twofactorqrcontainer">
<div id="twofactorqr"></div>
<button class="btn btn-default" onclick="$(\'#twofactorkeycontainer\').show(); $(\'#twofactorqrcontainer\').hide();">Manual</button>
</div>';
echo '<div id="twofactorkeycontainer">
<form id="twofactorkey" class="form-horizontal" role="form">'.$twofactor['text'].'</form>
<button class="btn btn-default" onclick="$(\'#twofactorkeycontainer\').hide(); $(\'#twofactorqrcontainer\').show();">QR</button>
</div>';
echo '<script>$("#twofactorqr").qrcode({"text": "'.$twofactor['uri'].'"}); $("#twofactorkeycontainer").hide();</script>';
echo '<br/><form method="post" class="form-horizontal" role="form">
<input type="hidden" name="twofactorremove" value="1" />
<button class="btn btn-danger" type="submit">Disable TwoFactor</button>
</form>';
} else {
if( isset($_POST['gentwofactorkey']) && isset($_POST['twofactortype']) ) {
require_once($config['install_dir']."/html/includes/authentication/twofactor.lib.php");
$chk = dbFetchRow("SELECT twofactor FROM users WHERE username = ?", array($_SESSION['username']));
if( empty($chk['twofactor']) ) {
$twofactor = array('key' => twofactor_genkey());
if( $_POST['twofactortype'] == "counter" ) {
$twofactor['counter'] = 1;
} else {
$twofactor['counter'] = false;
}
if( !dbUpdate(array('twofactor' => json_encode($twofactor)),'users','username = ?',array($_SESSION['username'])) ) {
echo '<div class="alert alert-danger">Error inserting TwoFactor details. Please try again later and contact Administrator if error persists.</div>';
} else {
echo '<div class="alert alert-success">Added TwoFactor credentials. Please reload page.</div><script>window.location = "/preferences/";</script>';
}
} else {
echo '<div class="alert alert-danger">TwoFactor credentials already exists.</div>';
}
} else {
echo '<form method="post" class="form-horizontal" role="form">
<input type="hidden" name="gentwofactorkey" value="1" />
<div class="form-group">
<label for="twofactortype" class="col-sm-2 control-label">TwoFactor Type</label>
<div class="col-sm-4">
<select name="twofactortype">
<option value=""></option>
<option value="counter">Counter Based (HOTP)</option>
<option value="time">Time Based (TOTP)</option>
</select>
</div>
</div>
<button class="btn btn-default" type="submit">Generate TwoFactor Secret Key</button>
</form>';
}
}
echo '</div>';
}
}
echo("<div style='background-color: #e5e5e5; border: solid #e5e5e5 10px; margin-bottom:10px;'>");
echo("<div style='font-size: 18px; font-weight: bold; margin-bottom: 5px;'>Device Permissions</div>");