mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
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:
72
doc/TwoFactor.md
Normal file
72
doc/TwoFactor.md
Normal file
@ -0,0 +1,72 @@
|
||||
Table of Content:
|
||||
- [About](#about)
|
||||
- [Types](#types)
|
||||
- [Timebased One-Time-Password (TOTP)](#totp)
|
||||
- [Counterbased One-Time-Password (HOTP)](#hotp)
|
||||
- [Configuration](#config)
|
||||
- [Usage](#usage)
|
||||
- [Google Authenticator](#usage-google)
|
||||
|
||||
# <a name="about">About</a>
|
||||
|
||||
Over the last couple of years, the primary attack vector for internet accounts has been static passwords.
|
||||
Therefore static passwords are no longer suffient to protect unauthorized access to accounts.
|
||||
Two Factor Authentication adds a variable part in authentication procedures.
|
||||
A user is now required to supply a changing 6-digit passcode in addition to it's password to obtain access to the account.
|
||||
|
||||
LibreNMS has a RFC4226 conform implementation of both Time and Counter based One-Time-Passwords.
|
||||
It also allows the administrator to configure a throttle time to enforce after 3 failures exceeded. Unlike RFC4226 suggestions, this throttle time will not stack on the amount of failures.
|
||||
|
||||
# <a name="types">Types</a>
|
||||
|
||||
In general, these two types do not differ in algorithmic terms.
|
||||
The types only differ in the variable being used to derive the passcodes from.
|
||||
The underlying HMAC-SHA1 remains the same for both types, security advantages or disadvantages of each are discussed further down.
|
||||
|
||||
## <a name="totp">Timebased One-Time-Password (TOTP)</a>
|
||||
|
||||
Like the name suggests, this type uses the current Time or a subset of it to generate the passcodes.
|
||||
These passcodes solely rely on the secrecy of their Secretkey in order to provide passcodes.
|
||||
An attacker only needs to guess that Secretkey and the other variable part is any given time, presumably the time upon login.
|
||||
RFC4226 suggests a resynchronization attempt in case the passcode mismatches, providing the attacker a range of upto +/- 3 Minutes to create passcodes.
|
||||
|
||||
|
||||
## <a name="hotp">Counterbased One-Time-Password (TOTP)</a>
|
||||
|
||||
This type uses an internal counter that needs to be in-synch with the server's counter to successfully authenticate the passcodes.
|
||||
The main advantage over timebased OTP is the attacker doesnt only need to know the Secretkey but also the server's Counter in order to create valid passcodes.
|
||||
RFC4226 suggests a resynchronization attempt in case the passcode mismatches, providing the attacker a range of upto +4 increments from the actual counter to create passcodes.
|
||||
|
||||
# <a name="config">Configuration</a>
|
||||
|
||||
Enable Two-Factor:
|
||||
```php
|
||||
$config['twofactor'] = true;
|
||||
```
|
||||
|
||||
Set throttle-time (in secconds):
|
||||
```php
|
||||
$config['twofactor_lock'] = 300;
|
||||
```
|
||||
|
||||
# <a name="usage">Usage</a>
|
||||
|
||||
These steps imply that TwoFactor has been enabled in your `config.php`
|
||||
|
||||
Create a Two-Factor key:
|
||||
- Go to 'My Settings' (/preferences/)
|
||||
- Choose TwoFactor type
|
||||
- Click on 'Generate TwoFactor Secret Key'
|
||||
- If your browser didnt reload, reload manually
|
||||
- Scan provided QR or click on 'Manual' to see the Key
|
||||
|
||||
## <a name="usage-google">Google Authenticator</a>
|
||||
|
||||
__Note__: Google Authenticator only allows counterbased OTP when scanned via QR codes.
|
||||
|
||||
Installation guides for Google Authneticator can be found [here](https://support.google.com/accounts/answer/1066447?hl=en).
|
||||
|
||||
Usage:
|
||||
- Create a key like described above
|
||||
- Scan provided QR or click on 'Manual' and type down the Secret
|
||||
- On next login, enter the passcode that the App provides
|
@ -75,10 +75,16 @@ if ((isset($_SESSION['username'])) || (isset($_COOKIE['sess_id'],$_COOKIE['token
|
||||
$_SESSION['user_id'] = get_userid($_SESSION['username']);
|
||||
if (!$_SESSION['authenticated'])
|
||||
{
|
||||
if( $config['twofactor'] === true && !isset($_SESSION['twofactor']) ) {
|
||||
require_once($config['install_dir'].'/html/includes/authentication/twofactor.lib.php');
|
||||
twofactor_auth();
|
||||
}
|
||||
if( !$config['twofactor'] || $_SESSION['twofactor'] ) {
|
||||
$_SESSION['authenticated'] = true;
|
||||
dbInsert(array('user' => $_SESSION['username'], 'address' => $_SERVER["REMOTE_ADDR"], 'result' => 'Logged In'), 'authlog');
|
||||
header("Location: ".$_SERVER['REQUEST_URI']);
|
||||
}
|
||||
}
|
||||
if (isset($_POST['remember']))
|
||||
{
|
||||
$sess_id = session_id();
|
||||
|
231
html/includes/authentication/twofactor.lib.php
Normal file
231
html/includes/authentication/twofactor.lib.php
Normal file
@ -0,0 +1,231 @@
|
||||
<?php
|
||||
/* Copyright (C) 2014 Daniel Preussker <f0o@devilcode.org>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/**
|
||||
* Two-Factor Authentication Library
|
||||
* @author f0o <f0o@devilcode.org>
|
||||
* @copyright 2014 f0o, LibreNMS
|
||||
* @license GPL
|
||||
* @package LibreNMS
|
||||
* @subpackage Authentication
|
||||
*/
|
||||
|
||||
/**
|
||||
* Key Interval in seconds.
|
||||
* Set to 30s due to Google-Authenticator limitation.
|
||||
* Sadly Google-Auth is the most used Non-Physical OTP app.
|
||||
*/
|
||||
const keyInterval = 30;
|
||||
|
||||
/**
|
||||
* Size of the OTP.
|
||||
* Set to 6 for the same reasons as above.
|
||||
*/
|
||||
const otpSize = 6;
|
||||
|
||||
/**
|
||||
* Window to honour whilest verifying OTP.
|
||||
*/
|
||||
const otpWindow = 4;
|
||||
|
||||
/**
|
||||
* Base32 Decoding dictionary
|
||||
*/
|
||||
$base32 = array(
|
||||
"A" => 0, "B" => 1, "C" => 2, "D" => 3,
|
||||
"E" => 4, "F" => 5, "G" => 6, "H" => 7,
|
||||
"I" => 8, "J" => 9, "K" => 10, "L" => 11,
|
||||
"M" => 12, "N" => 13, "O" => 14, "P" => 15,
|
||||
"Q" => 16, "R" => 17, "S" => 18, "T" => 19,
|
||||
"U" => 20, "V" => 21, "W" => 22, "X" => 23,
|
||||
"Y" => 24, "Z" => 25, "2" => 26, "3" => 27,
|
||||
"4" => 28, "5" => 29, "6" => 30, "7" => 31
|
||||
);
|
||||
|
||||
/**
|
||||
* Base32 Encoding dictionary
|
||||
*/
|
||||
$base32_enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
/**
|
||||
* Generate Secret Key
|
||||
* @return string
|
||||
*/
|
||||
function twofactor_genkey() {
|
||||
global $base32_enc;
|
||||
// RFC 4226 recommends 160bits Secret Keys, that's 20 Bytes for the lazy ones.
|
||||
$crypto = false;
|
||||
$raw = "";
|
||||
$x = -1;
|
||||
while( $crypto == false || ++$x < 10 ) {
|
||||
$raw = openssl_random_pseudo_bytes(20,$crypto);
|
||||
}
|
||||
// RFC 4648 Base32 Encoding without padding
|
||||
$len = strlen($raw);
|
||||
$bin = "";
|
||||
$x = -1;
|
||||
while( ++$x < $len ) {
|
||||
$bin .= str_pad(base_convert(ord($raw[$x]), 10, 2), 8, '0', STR_PAD_LEFT);
|
||||
}
|
||||
$bin = str_split($bin, 5);
|
||||
$ret = "";
|
||||
$x = -1;
|
||||
while( ++$x < sizeof($bin) ) {
|
||||
$ret .= $base32_enc[base_convert(str_pad($bin[$x], 5, '0'), 2, 10)];
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate HOTP (RFC 4226)
|
||||
* @param string $key Secret Key
|
||||
* @param int|boolean $counter Optional Counter, Defaults to Timestamp
|
||||
* @return int
|
||||
*/
|
||||
function oath_hotp($key, $counter=false) {
|
||||
global $base32;
|
||||
if( $counter === false ) {
|
||||
$counter = floor(microtime(true)/keyInterval);
|
||||
}
|
||||
$length = strlen($key);
|
||||
$x = -1;
|
||||
$y = $z = 0;
|
||||
$kbin = "";
|
||||
while( ++$x < $length ) {
|
||||
$y <<= 5;
|
||||
$y += $base32[$key[$x]];
|
||||
$z += 5;
|
||||
if( $z >= 8 ) {
|
||||
$z -= 8;
|
||||
$kbin .= chr(($y & (0xFF << $z)) >> $z);
|
||||
}
|
||||
}
|
||||
$hash = hash_hmac('sha1', pack('N*', 0).pack('N*', $counter), $kbin, true);
|
||||
$offset = ord($hash[19]) & 0xf;
|
||||
$truncated = (((ord($hash[$offset+0]) & 0x7f) << 24 ) | ((ord($hash[$offset+1]) & 0xff) << 16 ) | ((ord($hash[$offset+2]) & 0xff) << 8 ) | (ord($hash[$offset+3]) & 0xff)) % pow(10, otpSize);
|
||||
return str_pad($truncated, otpSize, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify HOTP token honouring window
|
||||
* @param string $key Secret Key
|
||||
* @param int $otp OTP supplied by user
|
||||
* @param int|boolean $counter Counter, if false timestamp is used
|
||||
* @return boolean|int
|
||||
*/
|
||||
function verify_hotp($key,$otp,$counter=false) {
|
||||
if( oath_hotp($key,$counter) == $otp ) {
|
||||
return true;
|
||||
} else {
|
||||
if( $counter === false ) {
|
||||
//TimeBased HOTP requires lookbehind and lookahead.
|
||||
$counter = floor(microtime(true)/keyInterval);
|
||||
$initcount = $counter-((otpWindow+1)*keyInterval);
|
||||
$endcount = $counter+(otpWindow*keyInterval);
|
||||
$totp = true;
|
||||
} else {
|
||||
//Counter based HOTP only has lookahead, not lookbehind.
|
||||
$initcount = $counter-1;
|
||||
$endcount = $counter+otpWindow;
|
||||
$totp = false;
|
||||
}
|
||||
while( ++$initcount <= $endcount ) {
|
||||
if( oath_hotp($key,$initcount) == $otp ) {
|
||||
if( !$totp ) {
|
||||
return $initcount;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print TwoFactor Input-Form
|
||||
* @param boolean $form Include FORM-tags
|
||||
* @return void|string
|
||||
*/
|
||||
function twofactor_form($form=true){
|
||||
global $config;
|
||||
$ret = "";
|
||||
if( $form ) {
|
||||
$ret .= '
|
||||
<form class="form-horizontal" role="form" action="" method="post" name="twofactorform">';
|
||||
}
|
||||
$ret .= '
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<h3>Please Enter TwoFactor Token:</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="twofactor" class="col-sm-2 control-label">Token</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="twofactor" id="twofactor" class="form-control" autocomplete="off" placeholder="012345" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-6">
|
||||
<button type="submit" class="btn btn-default input-sm" name="submit" type="submit">Login</button>
|
||||
</div>
|
||||
</div>';
|
||||
$ret .= '<script>document.twofactorform.twofactor.focus();</script>';
|
||||
if( $form ) {
|
||||
$ret .= '
|
||||
</form>';
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication logic
|
||||
* @return void
|
||||
*/
|
||||
function twofactor_auth() {
|
||||
global $auth_message, $twofactorform, $config;
|
||||
$twofactor = dbFetchRow('SELECT twofactor FROM users WHERE username = ?', array($_SESSION['username']));
|
||||
if( empty($twofactor['twofactor']) ) {
|
||||
$_SESSION['twofactor'] = true;
|
||||
} else {
|
||||
$twofactor = json_decode($twofactor['twofactor'],true);
|
||||
if( $twofactor['fails'] >= 3 && (!$config['twofactor_lock'] || (time()-$twofactor['last']) < $config['twofactor_lock']) ) {
|
||||
$auth_message = "Too many failures, please ".($config['twofactor_lock'] ? "wait ".$config['twofactor_lock']." seconds" : "contact administrator").".";
|
||||
} else {
|
||||
if( !$_POST['twofactor'] ) {
|
||||
$twofactorform = true;
|
||||
} else {
|
||||
if( ($server_c = verify_hotp($twofactor['key'],$_POST['twofactor'],$twofactor['counter'])) === false ) {
|
||||
$twofactor['fails']++;
|
||||
$twofactor['last'] = time();
|
||||
$auth_message = "Wrong Two-Factor Token.";
|
||||
} else {
|
||||
if( $twofactor['counter'] !== false ) {
|
||||
if( $server_c !== true && $server_c !== $twofactor['counter'] ) {
|
||||
$twofactor['counter'] = $server_c+1;
|
||||
} else {
|
||||
$twofactor['counter']++;
|
||||
}
|
||||
}
|
||||
$twofactor['fails'] = 0;
|
||||
$_SESSION['twofactor'] = true;
|
||||
}
|
||||
dbUpdate(array('twofactor' => json_encode($twofactor)),'users','username = ?',array($_SESSION['username']));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
2
html/js/jquery.qrcode.min.js
vendored
Normal file
2
html/js/jquery.qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -270,6 +270,26 @@ if ($_SESSION['userlevel'] != '10') { include("includes/error-no-perm.inc.php");
|
||||
$vars['new_email'] = $users_details['email'];
|
||||
}
|
||||
|
||||
if( $config['twofactor'] ) {
|
||||
if( $vars['twofactorremove'] ) {
|
||||
if( dbUpdate(array('twofactor'=>''),users,'user_id = ?',array($vars['user_id'])) ) {
|
||||
echo "<div class='alert alert-success'>TwoFactor credentials removed.</div>";
|
||||
} else {
|
||||
echo "<div class='alert alert-danger'>Couldnt remove user's TwoFactor credentials.</div>";
|
||||
}
|
||||
}
|
||||
if( $vars['twofactorunlock'] ) {
|
||||
$twofactor = dbFetchRow("SELECT twofactor FROM users WHERE user_id = ?",array($vars['user_id']));
|
||||
$twofactor = json_decode($twofactor['twofactor'],true);
|
||||
$twofactor['fails'] = 0;
|
||||
if( dbUpdate(array('twofactor'=>json_encode($twofactor)),users,'user_id = ?',array($vars['user_id'])) ) {
|
||||
echo "<div class='alert alert-success'>User unlocked.</div>";
|
||||
} else {
|
||||
echo "<div class='alert alert-danger'>Couldnt reset user's TwoFactor failures.</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo("<form class='form-horizontal' role='form' method='post' action=''>
|
||||
<input type='hidden' name='user_id' value='" . $vars['user_id'] . "'>
|
||||
<input type='hidden' name='edit' value='yes'>
|
||||
@ -314,6 +334,33 @@ if ($_SESSION['userlevel'] != '10') { include("includes/error-no-perm.inc.php");
|
||||
</div>
|
||||
<button type='submit' class='btn btn-default'>Update User</button>
|
||||
</form>");
|
||||
if( $config['twofactor'] ) {
|
||||
echo "<br/><div class='well'><h3>Two-Factor Authentication</h3>";
|
||||
$twofactor = dbFetchRow("SELECT twofactor FROM users WHERE user_id = ?",array($vars['user_id']));
|
||||
$twofactor = json_decode($twofactor['twofactor'],true);
|
||||
if( $twofactor['fails'] >= 3 && (!$config['twofactor_lock'] || (time()-$twofactor['last']) < $config['twofactor_lock']) ) {
|
||||
echo "<form class='form-horizontal' role='form' method='post' action=''>
|
||||
<input type='hidden' name='user_id' value='" . $vars['user_id'] . "'>
|
||||
<input type='hidden' name='edit' value='yes'>
|
||||
<div class='form-group'>
|
||||
<label for='twofactorunlock' class='col-sm-2 control-label'>User exceeded failures</label>
|
||||
<input type='hidden' name='twofactorunlock' value='1'>
|
||||
<button type='submit' class='btn btn-default'>Unlock</button>
|
||||
</div>
|
||||
</form>";
|
||||
}
|
||||
if( $twofactor['key'] ) {
|
||||
echo "<form class='form-horizontal' role='form' method='post' action=''>
|
||||
<input type='hidden' name='user_id' value='" . $vars['user_id'] . "'>
|
||||
<input type='hidden' name='edit' value='yes'>
|
||||
<input type='hidden' name='twofactorremove' value='1'>
|
||||
<button type='submit' class='btn btn-danger'>Disable TwoFactor</button>
|
||||
</form>
|
||||
</div>";
|
||||
} else {
|
||||
echo "<p>No TwoFactor key generated for this user, Nothing to do.</p>";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo print_error("Error getting user details");
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
<?php
|
||||
if( $config['twofactor'] && isset($twofactorform) ) {
|
||||
echo twofactor_form();
|
||||
} else { ?>
|
||||
<form class="form-horizontal" role="form" action="" method="post" name="logonform">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
@ -56,6 +60,8 @@ if (isset($config['login_message']))
|
||||
document.logonform.username.focus();
|
||||
// -->
|
||||
</script>
|
||||
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -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>");
|
||||
|
||||
|
1
sql-schema/038.sql
Normal file
1
sql-schema/038.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE `users` ADD `twofactor` VARCHAR( 255 ) NOT NULL;
|
Reference in New Issue
Block a user