Merge branch 'feature/ticket#1579-TwoFactorAuthentication' into develop

Resolved conflicts:
	pandora_console/extras/pandoradb_migrate_5.1_to_6.0.mysql.sql
	pandora_console/extras/pandoradb_migrate_5.1_to_6.0.oracle.sql
	pandora_console/extras/pandoradb_migrate_5.1_to_6.0.postgreSQL.sql
	pandora_console/include/styles/pandora.css
This commit is contained in:
Alejandro Gallardo Escobar 2014-12-15 15:06:29 +01:00
commit 15d5607787
18 changed files with 1801 additions and 218 deletions

View File

@ -30,3 +30,16 @@ SET t1.id_policy_module = (
SELECT t2.id_policy_module
FROM tagente_modulo AS t2
WHERE t1.id_agente_modulo = t2.id_agente_modulo);
/* 2014/12/10 */
-- ----------------------------------------------------------------------
-- Table `tuser_double_auth`
-- ----------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `tuser_double_auth` (
`id` int(10) unsigned NOT NULL auto_increment,
`id_user` varchar(60) NOT NULL,
`secret` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE (`id_user`),
FOREIGN KEY (`id_user`) REFERENCES tusuario(`id_user`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -18,4 +18,16 @@ ALTER TABLE tlayout_data ADD COLUMN fill_color varchar(200) DEFAULT "";
-- Table `ttag_module`
-- ---------------------------------------------------------------------
ALTER TABLE tlayout_data ADD COLUMN id_policy_module NUMBER(10, 0) DEFAULT 0 NOT NULL;
ALTER TABLE tlayout_data ADD COLUMN id_policy_module NUMBER(10, 0) DEFAULT 0 NOT NULL;
/* 2014/12/10 */
-- ----------------------------------------------------------------------
-- Table `tuser_double_auth`
-- ----------------------------------------------------------------------
CREATE TABLE tuser_double_auth (
id NUMBER(10, 0) NOT NULL PRIMARY KEY,
id_user VARCHAR2(60) NOT NULL REFERENCES tusuario(id_user) ON DELETE CASCADE,
secret VARCHAR2(20) NOT NULL
);
CREATE SEQUENCE tuser_double_auth_s INCREMENT BY 1 START WITH 1;
CREATE OR REPLACE TRIGGER tuser_double_auth_inc BEFORE INSERT ON tuser_double_auth REFERENCING NEW AS NEW FOR EACH ROW BEGIN SELECT tuser_double_auth_s.nextval INTO :NEW.ID FROM dual; END tuser_double_auth_inc;;

View File

@ -18,4 +18,14 @@ ALTER TABLE "tlayout_data" ADD COLUMN "fill_color" varchar(200) DEFAULT "";
-- Table `ttag_module`
-- ---------------------------------------------------------------------
ALTER TABLE tlayout_data ADD COLUMN "id_policy_module" INTEGER NOT NULL DEFAULT 0;
ALTER TABLE tlayout_data ADD COLUMN "id_policy_module" INTEGER NOT NULL DEFAULT 0;
/* 2014/12/10 */
-- ----------------------------------------------------------------------
-- Table `tuser_double_auth`
-- ----------------------------------------------------------------------
CREATE TABLE "tuser_double_auth" (
"id" SERIAL NOT NULL PRIMARY KEY,
"id_user" varchar(60) NOT NULL UNIQUE REFERENCES "tusuario"("id_user") ON DELETE CASCADE,
"secret" varchar(20) NOT NULL
);

View File

@ -35,6 +35,7 @@ switch ($login_screen) {
$logo_title = __('Go to Pandora FMS Website');
break;
case 'logout':
case 'double_auth':
$logo_link = 'index.php';
$logo_title = __('Go to Login');
break;
@ -129,6 +130,22 @@ echo '
echo __('Your session is over. Please close your browser window to close this Pandora session.').'<br /><br />';
echo '</p>';
break;
case 'double_auth':
if (!empty ($page) && !empty ($sec)) {
foreach ($_POST as $key => $value) {
html_print_input_hidden ($key, $value);
}
}
echo '<div class="login_double_auth_code_text">';
echo __('Authenticator code') . '<br>';
echo '</div>';
echo '<div class="login_double_auth_code">';
html_print_input_text_extended ("auth_code", '', "auth_code", '', '', '' , false, '', 'class="login login_password"', false, true);
echo '</div>';
echo '<div class="login_button">';
html_print_submit_button(__("Check code") . '&nbsp;&nbsp;>', "login_button", false, 'class="sub next_login"');
echo '</div>';
break;
default:
if (isset($error_info)) {
echo '<h1 id="log_title">' . $error_info['title'] . '</h1>';

View File

@ -94,6 +94,15 @@ if (enterprise_installed()) {
add_enterprise_auth_options($table, 12);
}
// Enable double authentication
$row = array();
$row[] = __('Double authentication')
. ui_print_help_tip(__("If this option is enabled, the users can use double authentication with their accounts"), true);
$row[] = __('Yes').'&nbsp;'.html_print_radio_button('double_auth_enabled', 1, '', $config['double_auth_enabled'], true)
.'&nbsp;&nbsp;'
. __('No').'&nbsp;'.html_print_radio_button('double_auth_enabled', 0, '', $config['double_auth_enabled'], true);
$table->data[] = $row;
echo '<form id="form_setup" method="post">';
html_print_input_hidden ('update_config', 1);
html_print_table ($table);

View File

@ -0,0 +1,522 @@
<?php
// Pandora FMS - http://pandorafms.com
// ==================================================
// Copyright (c) 2005-2010 Artica Soluciones Tecnologicas
// Please see http://pandorafms.org for full contribution list
// 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 for version 2.
// 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.
global $config;
// Login check
check_login ();
// Security check
$id_user = (string) get_parameter('id_user');
if ($id_user !== $config['id_user']) {
db_pandora_audit("ACL Violation",
"Trying to access Double Authentication");
echo json_encode(-1);
return;
}
// Load the class
require_once ($config['homedir'].'/include/auth/GAuth/Auth.php');
// Default lenght of the secret
$secret_lenght = 16;
// Default lenght of the code
$code_lenght = 6;
// Generate a new secret for the user
$generate_double_auth_secret = (bool) get_parameter('generate_double_auth_secret');
if ($generate_double_auth_secret) {
$gAuth = new \GAuth\Auth();
$code = $gAuth->generateCode($secret_lenght);
echo json_encode($code);
return;
}
// Validate the provided secret with a code provided by the user.
// If the parameter 'save' is set to true, the secret will
// be stored into the database.
// The results can be true, false or 1 if the validation is true
// but the secret can't be stored into the database.
$validate_double_auth_code = (bool) get_parameter('validate_double_auth_code');
if ($validate_double_auth_code) {
$result = false;
$secret = (string) get_parameter('secret');
if (!empty($secret) && strlen($secret) === $secret_lenght) {
$code = (string) get_parameter('code');
if (!empty($code) && strlen($code) === $code_lenght) {
$save = (bool) get_parameter('save');
if (!empty($code)) {
$gAuth = new \GAuth\Auth($secret);
$result = $gAuth->validateCode($code);
}
if ($result && $save) {
// Delete the actual value (if exists)
$where = array(
'id_user' => $id_user
);
db_process_sql_delete('tuser_double_auth', $where);
// Insert the new value
$values = array(
'id_user' => $id_user,
'secret' => $secret
);
$result = (bool) db_process_sql_insert('tuser_double_auth', $values);
if (!$result) {
$result = 1;
}
}
}
}
echo json_encode($result);
return;
}
// Set the provided secret to the user
$save_double_auth_secret = (bool) get_parameter('save_double_auth_secret');
if ($save_double_auth_secret) {
$result = false;
$secret = (string) get_parameter('secret');
if (strlen($secret) === $secret_lenght) {
// Delete the actual value (if exists)
$where = array(
'id_user' => $id_user
);
db_process_sql_delete('tuser_double_auth', $where);
// Insert the new value
$values = array(
'id_user' => $id_user,
'secret' => $secret
);
$result = (bool) db_process_sql_insert('tuser_double_auth', $values);
}
echo json_encode($result);
return;
}
// Disable the double auth for the user
$deactivate_double_auth = (bool) get_parameter('deactivate_double_auth');
if ($deactivate_double_auth) {
$result = false;
// Delete the actual value (if exists)
$where = array(
'id_user' => $id_user
);
$result = db_process_sql_delete('tuser_double_auth', $where);
echo json_encode($result);
return;
}
// Get the info page to the container dialog
$get_double_auth_data_page = (bool) get_parameter('get_double_auth_data_page');
if ($get_double_auth_data_page) {
$secret = db_get_value('secret', 'tuser_double_auth', 'id_user', $id_user);
if (empty($secret)) {
return;
}
$html = '';
$html .= "<div class=\"left_align\">";
$html .= "<p>";
$html .= __('This is the private code that you should use with your authenticator app') . ". ";
$html .= __('You could enter the code manually or use the QR code to add it automatically') . ".";
$html .= "</p>";
$html .= "</div>";
$html .= "<div class=\"center_align\">";
$html .= __('Code') . ": <b>$secret</b>";
$html .= "<br>";
$html .= __('QR') . ": <br>";
$html .= "<div id=\"qr-container\"></div>";
$html .= "</div>";
ob_clean();
?>
<script type="text/javascript">
var secret = "<?php echo $secret; ?>";
var userID = "<?php echo $config['id_user']; ?>";
// QR code with the secret to add it to the app
paint_qrcode("otpauth://totp/"+userID+"?secret="+secret, $("div#qr-container").get(0), 200, 200);
$("div#qr-container").attr("title", "").find("canvas").remove();
// Don't delete this timeout. It's necessary to perform the style change.
// Chrome min. milliseconds: 1.
// Firefox min. milliseconds: 9.
setTimeout(function() {
$("div#qr-container").find("img").attr("style", "");
}, 10);
</script>
<?php
$html .= ob_get_clean();
echo $html;
return;
}
// Get the info page to the container dialog
$get_double_auth_info_page = (bool) get_parameter('get_double_auth_info_page');
if ($get_double_auth_info_page) {
$container_id = (string) get_parameter('containerID');
$html = '';
$html .= "<div class=\"left_align\">";
$html .= "<p>";
$html .= __('You are about to activate the double authentication') . ". ";
$html .= __('With this option enabled, your account access will be more secure,
cause a code generated by other application will be required after the login') . ". ";
$html .= "</p>";
$html .= "<p>";
$html .= __('You will need to install the app from the following link before continue') . ". ";
$html .= "</p>";
$html .= "</div>";
$html .= "<br>";
$html .= "<div class=\"center_align\">";
$html .= html_print_button(__('Download the app'), 'google_authenticator_download', false, '', '', true);
$html .= "</div>";
$html .= "<br>";
$html .= "<div class=\"center_align\">";
$html .= html_print_button(__('Continue'), 'continue_to_generate', false, '', '', true);
$html .= "</div>";
ob_clean();
?>
<script type="text/javascript">
// Open the download page on click
$("input[name=\"google_authenticator_download\"]").click(function (e) {
e.preventDefault();
window.open("https://support.google.com/accounts/answer/1066447");
});
// Change the container content with the generation page
$("input[name=\"continue_to_generate\"]").click(function (e) {
e.preventDefault();
if (!confirm("<?php echo __('Are you installed the app yet?'); ?>")) {
return false;
}
var containerID = "<?php echo $container_id; ?>";
$("#"+containerID).html("<img src=\"<?php echo $config['homeurl']; ?>/images/spinner.gif\" />");
$.ajax({
url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",
type: 'POST',
dataType: 'html',
data: {
page: 'include/ajax/double_auth.ajax',
id_user: "<?php echo $config['id_user']; ?>",
get_double_auth_generation_page: 1,
containerID: containerID
},
complete: function(xhr, textStatus) {
},
success: function(data, textStatus, xhr) {
// isNaN = is not a number
if (isNaN(data)) {
$("#"+containerID).html(data);
}
// data is a number, convert it to integer to do the compare
else if (Number(data) === -1) {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('Authentication error') . '</div></b>'; ?>");
}
else {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('Error') . '</div></b>'; ?>");
}
},
error: function(xhr, textStatus, errorThrown) {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('There was an error loading the data') . '</div></b>'; ?>");
}
});
});
</script>
<?php
$html .= ob_get_clean();
echo $html;
return;
}
// Get the page that generates a secret for the user
$get_double_auth_generation_page = (bool) get_parameter('get_double_auth_generation_page');
if ($get_double_auth_generation_page) {
$container_id = (string) get_parameter('containerID');
$gAuth = new \GAuth\Auth();
$secret = $gAuth->generateCode($secret_lenght);
$html = '';
$html .= "<div class=\"center_align\">";
$html .= "<p>";
$html .= "<b>" . __('A private code has been generated') . "</b>.";
$html .= "</p>";
$html .= "</div>";
$html .= "<div class=\"left_align\">";
$html .= "<p>";
$html .= __('Before continue, you should create a new entry into the authenticator app') . ". ";
$html .= __('You could enter the code manually or use the QR code to add it automatically') . ".";
$html .= "</p>";
$html .= "</div>";
$html .= "<div class=\"center_align\">";
$html .= __('Code') . ": <b>$secret</b>";
$html .= "<br>";
$html .= __('QR') . ": <br>";
$html .= "<div id=\"qr-container\"></div>";
$html .= "<br>";
$html .= html_print_button(__('Refresh code'), 'continue_to_generate', false, '', '', true);
$html .= "&nbsp;";
$html .= html_print_button(__('Continue'), 'continue_to_validate', false, '', '', true);
$html .= "</div>";
ob_clean();
?>
<script type="text/javascript">
var secret = "<?php echo $secret; ?>";
var userID = "<?php echo $config['id_user']; ?>";
// QR code with the secret to add it to the app
paint_qrcode("otpauth://totp/"+userID+"?secret="+secret, $("div#qr-container").get(0), 200, 200);
$("div#qr-container").attr("title", "").find("canvas").remove();
// Don't delete this timeout. It's necessary to perform the style change.
// Chrome min. milliseconds: 1.
// Firefox min. milliseconds: 9.
setTimeout(function() {
$("div#qr-container").find("img").attr("style", "");
}, 10);
// Load the same page with another secret
$("input[name=\"continue_to_generate\"]").click(function(e) {
e.preventDefault();
var containerID = "<?php echo $container_id; ?>";
$("#"+containerID).html("<img src=\"<?php echo $config['homeurl']; ?>/images/spinner.gif\" />");
$.ajax({
url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",
type: 'POST',
dataType: 'html',
data: {
page: 'include/ajax/double_auth.ajax',
id_user: userID,
get_double_auth_generation_page: 1,
containerID: containerID
},
complete: function(xhr, textStatus) {
},
success: function(data, textStatus, xhr) {
// isNaN = is not a number
if (isNaN(data)) {
$("#"+containerID).html(data);
}
// data is a number, convert it to integer to do the compare
else if (Number(data) === -1) {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('Authentication error') . '</div></b>'; ?>");
}
else {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('Error') . '</div></b>'; ?>");
}
},
error: function(xhr, textStatus, errorThrown) {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('There was an error loading the data') . '</div></b>'; ?>");
}
});
});
// Load the validation page
$("input[name=\"continue_to_validate\"]").click(function(e) {
e.preventDefault();
if (!confirm("<?php echo __('Are you introduced the code in the authenticator app yet?'); ?>")) {
return false;
}
var containerID = "<?php echo $container_id; ?>";
$("#"+containerID).html("<img src=\"<?php echo $config['homeurl']; ?>/images/spinner.gif\" />");
$.ajax({
url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",
type: 'POST',
dataType: 'html',
data: {
page: 'include/ajax/double_auth.ajax',
id_user: "<?php echo $config['id_user']; ?>",
get_double_auth_validation_page: 1,
secret: secret,
containerID: containerID
},
complete: function(xhr, textStatus) {
},
success: function(data, textStatus, xhr) {
// isNaN = is not a number
if (isNaN(data)) {
$("#"+containerID).html(data);
}
// data is a number, convert it to integer to do the compare
else if (Number(data) === -1) {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('Authentication error') . '</div></b>'; ?>");
}
else {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('Error') . '</div></b>'; ?>");
}
},
error: function(xhr, textStatus, errorThrown) {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('There was an error loading the data') . '</div></b>'; ?>");
}
});
});
</script>
<?php
$html .= ob_get_clean();
echo $html;
return;
}
// Get the validation page
$get_double_auth_validation_page = (bool) get_parameter('get_double_auth_validation_page');
if ($get_double_auth_validation_page) {
$container_id = (string) get_parameter('containerID');
$secret = (string) get_parameter('secret');
if (empty($secret) || strlen($secret) != $secret_lenght) {
echo json_encode(false);
return;
}
$html = '';
$html .= "<div class=\"left_align\">";
$html .= "<p>";
$html .= __('Introduce a code generated by the app') . ". ";
$html .= __('If the code is valid, the double authentication will be activated') . ".";
$html .= "</p>";
$html .= "</div>";
$html .= "<br>";
$html .= "<div class=\"center_align\">";
$html .= html_print_input_text('code', '', '', 50, $secret_lenght, true);
$html .= "<div id=\"code_input_message\" class=\"red\"></div>";
$html .= "<br><br>";
$html .= "<div id=\"button-container\">";
$html .= html_print_button(__('Validate code'), 'continue_to_validate', false, '', '', true);
$html .= html_print_image ("images/spinner.gif", true);
$html .= "</div>";
$html .= "</div>";
ob_clean();
?>
<script type="text/javascript">
$("div#button-container").find("img").hide();
// Start the error message hiden
$("div#code_input_message").hide();
var secret = "<?php echo $secret; ?>";
$("input#text-code").keypress(function() {
$(this).removeClass("red").css('border-color', '#cbcbcb');
});
$("input[name=\"continue_to_validate\"]").click(function(e) {
e.preventDefault();
// Hide the error message
$("div#code_input_message").hide();
var containerID = "<?php echo $container_id; ?>";
$("input[name=\"continue_to_validate\"]").prop('enabled', false).hide();
$("div#button-container").find("img").show();
$.ajax({
url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",
type: 'POST',
dataType: 'json',
data: {
page: 'include/ajax/double_auth.ajax',
id_user: "<?php echo $config['id_user']; ?>",
validate_double_auth_code: 1,
save: 1,
secret: secret,
code: function () {
return $("input#text-code").val();
},
containerID: containerID
},
complete: function(xhr, textStatus) {
},
success: function(data, textStatus, xhr) {
// Valid code
if (data === true) {
$("#"+containerID).html("<b><?php echo '<b><div class=\"green\">' . __('The code is valid, you can exit now') . '</div></b>'; ?></b>");
}
// Invalid code
else if (data === false) {
$("input[name=\"continue_to_validate\"]").prop('enabled', true).show();
$("div#button-container").find("img").hide();
$("input#text-code").addClass("red").css('border-color', '#c00');
$("div#code_input_message").html("<?php echo __('Invalid code'); ?>").show();
}
// Valid code but not saved
else if (data === 1) {
$("input[name=\"continue_to_validate\"]").prop('enabled', true).show();
$("div#button-container").find("img").hide();
$("input#text-code").addClass("red").css('border-color', '#c00');
$("div#code_input_message").html("<?php echo __('The code is valid, but it was an error saving the data'); ?>").show();
}
// Authentication error
else if (data === -1) {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('Authentication error') . '</div></b>'; ?>");
}
// Not expected results
else {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('Error') . '</div></b>'; ?>");
}
},
error: function(xhr, textStatus, errorThrown) {
$("#"+containerID).html("<?php echo '<b><div class=\"red\">' . __('There was an error loading the data') . '</div></b>'; ?>");
}
});
});
</script>
<?php
$html .= ob_get_clean();
echo $html;
return;
}
return;
?>

View File

@ -0,0 +1,356 @@
<?php
// The MIT License (MIT)
// Copyright (c) 2013 Chris Cornutt
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
namespace GAuth;
/**
* A class for generating the codes compatible with the Google Authenticator
* clients.
*
* NOTE: A lot of the logic from this class has been borrowed from this class:
* http://www.idontplaydarts.com/wp-content/uploads/2011/07/ga.php_.txt
*
* @author Chris Cornutt <ccornutt@phpdeveloper.org>
* @package GAuth
* @license MIT
*/
class Auth
{
/**
* Internal lookup table
* @var array
*/
private $lookup = array();
/**
* Initialization key
* @var string
*/
private $initKey = null;
/**
* Seconds between key refreshes
* @var integer
*/
private $refreshSeconds = 30;
/**
* Length of codes to generate
* @var integer
*/
private $codeLength = 6;
/**
* Range plus/minus for "window of opportunity" on allowed codes
* @var integer
*/
private $range = 2;
/**
* Initialize the object and set up the lookup table
* Optionally the Initialization key
*
* @param string $initKey Initialization key
*/
public function __construct($initKey = null)
{
$this->buildLookup();
if ($initKey !== null) {
$this->setInitKey($initKey);
}
}
/**
* Build the base32 lookup table
*
* @return null
*/
public function buildLookup()
{
$lookup = array_combine(
array_merge(range('A', 'Z'), range(2, 7)),
range(0, 31)
);
$this->setLookup($lookup);
}
/**
* Get the current "range" value
* @return integer Range value
*/
public function getRange()
{
return $this->range;
}
/**
* Set the "range" value
*
* @param integer $range Range value
* @return \GAuth\Auth instance
*/
public function setRange($range)
{
if (!is_numeric($range)) {
throw new \InvalidArgumentException('Invalid window range');
}
$this->range = $range;
return $this;
}
/**
* Set the initialization key for the object
*
* @param string $key Initialization key
* @throws \InvalidArgumentException If hash is not valid base32
* @return \GAuth\Auth instance
*/
public function setInitKey($key)
{
if (preg_match('/^['.implode('', array_keys($this->getLookup())).']+$/', $key) == false) {
throw new \InvalidArgumentException('Invalid base32 hash!');
}
$this->initKey = $key;
return $this;
}
/**
* Get the current Initialization key
*
* @return string Initialization key
*/
public function getInitKey()
{
return $this->initKey;
}
/**
* Set the contents of the internal lookup table
*
* @param array $lookup Lookup data set
* @throws \InvalidArgumentException If lookup given is not an array
* @return \GAuth\Auth instance
*/
public function setLookup($lookup)
{
if (!is_array($lookup)) {
throw new \InvalidArgumentException('Lookup value must be an array');
}
$this->lookup = $lookup;
return $this;
}
/**
* Get the current lookup data set
*
* @return array Lookup data
*/
public function getLookup()
{
return $this->lookup;
}
/**
* Get the number of seconds for code refresh currently set
*
* @return integer Refresh in seconds
*/
public function getRefresh()
{
return $this->refreshSeconds;
}
/**
* Set the number of seconds to refresh codes
*
* @param integer $seconds Seconds to refresh
* @throws \InvalidArgumentException If seconds value is not numeric
* @return \GAuth\Auth instance
*/
public function setRefresh($seconds)
{
if (!is_numeric($seconds)) {
throw \InvalidArgumentException('Seconds must be numeric');
}
$this->refreshSeconds = $seconds;
return $this;
}
/**
* Get the current length for generated codes
*
* @return integer Code length
*/
public function getCodeLength()
{
return $this->codeLength;
}
/**
* Set the length of the generated codes
*
* @param integer $length Code length
* @return \GAuth\Auth instance
*/
public function setCodeLength($length)
{
$this->codeLength = $length;
return $this;
}
/**
* Validate the given code
*
* @param string $code Code entered by user
* @param string $initKey Initialization key
* @param string $timestamp Timestamp for calculation
* @param integer $range Seconds before/after to validate hash against
* @throws \InvalidArgumentException If incorrect code length
* @return boolean Pass/fail of validation
*/
public function validateCode($code, $initKey = null, $timestamp = null, $range = null)
{
if (strlen($code) !== $this->getCodeLength()) {
throw new \InvalidArgumentException('Incorrect code length');
}
$range = ($range == null) ? $this->getRange() : $range;
$timestamp = ($timestamp == null) ? $this->generateTimestamp() : $timestamp;
$initKey = ($initKey == null) ? $this->getInitKey() : $initKey;
$binary = $this->base32_decode($initKey);
for ($time = ($timestamp - $range); $time <= ($timestamp + $range); $time++) {
if ($this->generateOneTime($binary, $time) == $code) {
return true;
}
}
return false;
}
/**
* Generate a one-time code
*
* @param string $initKey Initialization key [optional]
* @param string $timestamp Timestamp for calculation [optional]
* @return string Geneerated code/hash
*/
public function generateOneTime($initKey = null, $timestamp = null)
{
$initKey = ($initKey == null) ? $this->getInitKey() : $initKey;
$timestamp = ($timestamp == null) ? $this->generateTimestamp() : $timestamp;
$hash = hash_hmac (
'sha1',
pack('N*', 0) . pack('N*', $timestamp),
$initKey,
true
);
return str_pad($this->truncateHash($hash), $this->getCodeLength(), '0', STR_PAD_LEFT);
}
/**
* Generate a code/hash
* Useful for making Initialization codes
*
* @param integer $length Length for the generated code
* @return string Generated code
*/
public function generateCode($length = 16)
{
$lookup = implode('', array_keys($this->getLookup()));
$code = '';
for ($i = 0; $i < $length; $i++) {
$code .= $lookup[mt_rand(0, strlen($lookup)-1)];
}
return $code;
}
/**
* Geenrate the timestamp for the calculation
*
* @return integer Timestamp
*/
public function generateTimestamp()
{
return floor(microtime(true)/$this->getRefresh());
}
/**
* Truncate the given hash down to just what we need
*
* @param string $hash Hash to truncate
* @return string Truncated hash value
*/
public function truncateHash($hash)
{
$offset = ord($hash[19]) & 0xf;
return (
((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, $this->getCodeLength());
}
/**
* Base32 decoding function
*
* @param string base32 encoded hash
* @throws \InvalidArgumentException When hash is not valid
* @return string Binary value of hash
*/
public function base32_decode($hash)
{
$lookup = $this->getLookup();
if (preg_match('/^['.implode('', array_keys($lookup)).']+$/', $hash) == false) {
throw new \InvalidArgumentException('Invalid base32 hash!');
}
$hash = strtoupper($hash);
$buffer = 0;
$length = 0;
$binary = '';
for ($i = 0; $i < strlen($hash); $i++) {
$buffer = $buffer << 5;
$buffer += $lookup[$hash[$i]];
$length += 5;
if ($length >= 8) {
$length -= 8;
$binary .= chr(($buffer & (0xFF << $length)) >> $length);
}
}
return $binary;
}
}

View File

@ -2236,4 +2236,55 @@ function print_audit_csv ($data) {
}
}
/**
* Validate the code given to surpass the 2 step authentication
*
* @param string User name
* @param string Code given by the authenticator app
*
* @return -1 if the parameters introduced are incorrect,
* there is a problem accessing the user secret or
* if an exception are launched.
* true if the code is valid.
* false if the code is invalid.
*/
function validate_double_auth_code ($user, $code) {
global $config;
require_once ($config['homedir'].'/include/auth/GAuth/Auth.php');
$result = false;
if (empty($user) || empty($code)) {
$result = -1;
}
else {
$secret = db_get_value('secret', 'tuser_double_auth', 'id_user', $user);
if ($secret === false) {
$result = -1;
}
else if (!empty($secret)) {
try {
$gAuth = new \GAuth\Auth($secret);
$result = $gAuth->validateCode($code);
} catch (Exception $e) {
$result = -1;
}
}
}
return $result;
}
/**
* Get if the 2 step authentication is enabled for the user given
*
* @param string User name
*
* @return true if the user has the double auth enabled or false otherwise.
*/
function is_double_auth_enabled ($user) {
$result = (bool) db_get_value('id', 'tuser_double_auth', 'id_user', $user);
return $result;
}
?>

View File

@ -321,6 +321,8 @@ function config_update_config () {
$error_update[] = __('User');
if (!config_update_value ('rintegria_pass', get_parameter ('rintegria_pass')))
$error_update[] = __('Password');
if (!config_update_value ('double_auth_enabled', get_parameter ('double_auth_enabled')))
$error_update[] = __('Double authentication');
/////////////
break;
case 'perf':

View File

@ -2820,3 +2820,17 @@ table#policy_modules td * {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
#dialog-double_auth-container {
width: 100%;
text-align: center;
vertical-align: middle;
}
.center_align {
text-align: center;
}
.left_align {
text-align: left;
}

View File

@ -167,176 +167,291 @@ if (strlen($search) > 0) {
$searchPage = true;
}
// Login process
if (! isset ($config['id_user']) && isset ($_GET["login"])) {
include_once('include/functions_db.php'); //Include it to use escape_string_sql function
$config["auth_error"] = ""; //Set this to the error message from the authorization mechanism
$nick = get_parameter_post ("nick"); //This is the variable with the login
$pass = get_parameter_post ("pass"); //This is the variable with the password
$nick = db_escape_string_sql($nick);
$pass = db_escape_string_sql($pass);
// process_user_login is a virtual function which should be defined in each auth file.
// It accepts username and password. The rest should be internal to the auth file.
// The auth file can set $config["auth_error"] to an informative error output or reference their internal error messages to it
// process_user_login should return false in case of errors or invalid login, the nickname if correct
$nick_in_db = process_user_login ($nick, $pass);
$expired_pass = false;
if (($nick_in_db != false) && ((!is_user_admin($nick)
|| $config['enable_pass_policy_admin']))
&& (defined('PANDORA_ENTERPRISE'))
&& ($config['enable_pass_policy'])) {
include_once(ENTERPRISE_DIR . "/include/auth/mysql.php");
// Login process
if (! isset ($config['id_user'])) {
if (isset ($_GET["login"])) {
include_once('include/functions_db.php'); //Include it to use escape_string_sql function
$blocked = login_check_blocked($nick);
if ($blocked) {
require_once ('general/login_page.php');
db_pandora_audit("Password expired", "Password expired: ".$nick, $nick);
while (@ob_end_flush ());
exit ("</html>");
$config["auth_error"] = ""; //Set this to the error message from the authorization mechanism
$nick = get_parameter_post ("nick"); //This is the variable with the login
$pass = get_parameter_post ("pass"); //This is the variable with the password
$nick = db_escape_string_sql($nick);
$pass = db_escape_string_sql($pass);
//Since now, only the $pass variable are needed
unset ($_GET['pass'], $_POST['pass'], $_REQUEST['pass']);
// If the auth_code exists, we assume the user has come through the double auth page
if (isset ($_POST['auth_code'])) {
$double_auth_success = false;
// The double authentication is activated and the user has surpassed the first step (the login).
// Now the authentication code provided will be checked.
if (isset ($_SESSION['prepared_login_da'])) {
if (isset ($_SESSION['prepared_login_da']['id_user'])
&& isset ($_SESSION['prepared_login_da']['timestamp'])) {
// The user has a maximum of 5 minutes to introduce the double auth code
$dauth_period = SECONDS_2MINUTES;
$now = time();
$dauth_time = $_SESSION['prepared_login_da']['timestamp'];
if ($now - $dauth_period < $dauth_time) {
// Nick
$nick = $_SESSION["prepared_login_da"]['id_user'];
// Code
$code = (string) get_parameter_post ("auth_code");
if (!empty($code)) {
$result = validate_double_auth_code($nick, $code);
if ($result === true) {
// Double auth success
$double_auth_success = true;
}
else {
// Screen
$login_screen = 'double_auth';
// Error message
$config["auth_error"] = __("Invalid code");
if (!isset($_SESSION['prepared_login_da']['attempts']))
$_SESSION['prepared_login_da']['attempts'] = 0;
$_SESSION['prepared_login_da']['attempts']++;
}
}
else {
// Screen
$login_screen = 'double_auth';
// Error message
$config["auth_error"] = __("The code shouldn't be empty");
if (!isset($_SESSION['prepared_login_da']['attempts']))
$_SESSION['prepared_login_da']['attempts'] = 0;
$_SESSION['prepared_login_da']['attempts']++;
}
}
else {
// Expired login
unset ($_SESSION['prepared_login_da']);
// Error message
$config["auth_error"] = __('Expired login');
}
}
else {
// If the code doesn't exist, remove the prepared login
unset ($_SESSION['prepared_login_da']);
// Error message
$config["auth_error"] = __('Login error');
}
}
// If $_SESSION['prepared_login_da'] doesn't exist, the user have to do the login again
else {
// Error message
$config["auth_error"] = __('Login error');
}
// Remove the authenticator code
unset ($_POST['auth_code'], $code);
if (!$double_auth_success) {
$login_failed = true;
require_once ('general/login_page.php');
db_pandora_audit("Logon Failed", "Invalid double auth login: "
.$_SERVER['REMOTE_ADDR'], $_SERVER['REMOTE_ADDR']);
while (@ob_end_flush ());
exit ("</html>");
}
}
//Checks if password has expired
$check_status = check_pass_status($nick, $pass);
switch ($check_status) {
case PASSSWORD_POLICIES_FIRST_CHANGE: //first change
case PASSSWORD_POLICIES_EXPIRED: //pass expired
$expired_pass = true;
login_change_password($nick);
break;
if (isset ($double_auth_success) && $double_auth_success) {
// This values are true cause there are checked before complete the 2nd auth step
$nick_in_db = $_SESSION["prepared_login_da"]['id_user'];
$expired_pass = false;
}
}
if (($nick_in_db !== false) && $expired_pass) {
//login ok and password has expired
require_once ('general/login_page.php');
db_pandora_audit("Password expired",
"Password expired: " . $nick, $nick);
while (@ob_end_flush ());
exit ("</html>");
}
else if (($nick_in_db !== false) && (!$expired_pass)) {
//login ok and password has not expired
$process_login = true;
echo "<script type='text/javascript'>var process_login_ok = 1;</script>";
unset ($_GET["sec2"]);
$_GET["sec"] = "general/logon_ok";
$home_page ='';
if (isset($nick)) {
$user_info = users_get_user_by_id($nick);
$home_page = io_safe_output($user_info['section']);
$home_url = $user_info['data_section'];
if ($home_page != '') {
switch($home_page) {
case 'Event list':
$_GET["sec"] = "eventos";
$_GET["sec2"] = "operation/events/events";
break;
case 'Group view':
$_GET["sec"] = "estado";
$_GET["sec2"] = "operation/agentes/group_view";
break;
case 'Alert detail':
$_GET["sec"] = "estado";
$_GET["sec2"] = "operation/agentes/alerts_status";
break;
case 'Tactical view':
$_GET["sec"] = "estado";
$_GET["sec2"] = "operation/agentes/tactical";
break;
case 'Default':
$_GET["sec"] = "general/logon_ok";
break;
case 'Dashboard':
$_GET["sec"] = "dashboard";
$_GET["sec2"] = ENTERPRISE_DIR.'/dashboard/main_dashboard';
break;
case 'Visual console':
$_GET["sec"] = "visualc";
$_GET["sec2"] = "operation/visual_console/index";
break;
case 'Other':
$home_url = io_safe_output($home_url);
parse_str ($home_url, $res);
$_GET["sec"] = $res["sec"];
$_GET["sec2"] = $res["sec2"];
else {
// process_user_login is a virtual function which should be defined in each auth file.
// It accepts username and password. The rest should be internal to the auth file.
// The auth file can set $config["auth_error"] to an informative error output or reference their internal error messages to it
// process_user_login should return false in case of errors or invalid login, the nickname if correct
$nick_in_db = process_user_login ($nick, $pass);
$expired_pass = false;
if (($nick_in_db != false) && ((!is_user_admin($nick)
|| $config['enable_pass_policy_admin']))
&& (defined('PANDORA_ENTERPRISE'))
&& ($config['enable_pass_policy'])) {
include_once(ENTERPRISE_DIR . "/include/auth/mysql.php");
$blocked = login_check_blocked($nick);
if ($blocked) {
require_once ('general/login_page.php');
db_pandora_audit("Password expired", "Password expired: ".$nick, $nick);
while (@ob_end_flush ());
exit ("</html>");
}
//Checks if password has expired
$check_status = check_pass_status($nick, $pass);
switch ($check_status) {
case PASSSWORD_POLICIES_FIRST_CHANGE: //first change
case PASSSWORD_POLICIES_EXPIRED: //pass expired
$expired_pass = true;
login_change_password($nick);
break;
}
}
else {
$_GET["sec"] = "general/logon_ok";
}
}
db_logon ($nick_in_db, $_SERVER['REMOTE_ADDR']);
$_SESSION['id_usuario'] = $nick_in_db;
$config['id_user'] = $nick_in_db;
//Remove everything that might have to do with people's passwords or logins
unset ($_GET['pass'], $pass, $_POST['pass'], $_REQUEST['pass'], $login_good);
$user_language = get_user_language($config['id_user']);
$l10n = NULL;
if (file_exists ('./include/languages/' . $user_language . '.mo')) {
$l10n = new gettext_reader (new CachedFileReader ('./include/languages/'.$user_language.'.mo'));
$l10n->load_tables();
}
}
else { //login wrong
$blocked = false;
if ((!is_user_admin($nick) || $config['enable_pass_policy_admin']) && defined('PANDORA_ENTERPRISE')) {
$blocked = login_check_blocked($nick);
}
if (!$blocked) {
if (defined('PANDORA_ENTERPRISE')) {
login_check_failed($nick); //Checks failed attempts
}
$login_failed = true;
if (($nick_in_db !== false) && $expired_pass) {
//login ok and password has expired
require_once ('general/login_page.php');
db_pandora_audit("Logon Failed", "Invalid login: ".$nick, $nick);
db_pandora_audit("Password expired",
"Password expired: " . $nick, $nick);
while (@ob_end_flush ());
exit ("</html>");
}
else if (($nick_in_db !== false) && (!$expired_pass)) {
//login ok and password has not expired
// Double auth check
if ((!isset ($double_auth_success) || !$double_auth_success) && is_double_auth_enabled($nick_in_db)) {
// Store this values in the session to know if the user login was correct
$_SESSION['prepared_login_da'] = array(
'id_user' => $nick_in_db,
'timestamp' => time(),
'attempts' => 0
);
// Load the page to introduce the double auth code
$login_screen = 'double_auth';
require_once ('general/login_page.php');
while (@ob_end_flush ());
exit ("</html>");
}
//login ok and password has not expired
$process_login = true;
echo "<script type='text/javascript'>var process_login_ok = 1;</script>";
unset ($_GET["sec2"]);
$_GET["sec"] = "general/logon_ok";
$home_page ='';
if (isset($nick)) {
$user_info = users_get_user_by_id($nick);
$home_page = io_safe_output($user_info['section']);
$home_url = $user_info['data_section'];
if ($home_page != '') {
switch($home_page) {
case 'Event list':
$_GET["sec"] = "eventos";
$_GET["sec2"] = "operation/events/events";
break;
case 'Group view':
$_GET["sec"] = "estado";
$_GET["sec2"] = "operation/agentes/group_view";
break;
case 'Alert detail':
$_GET["sec"] = "estado";
$_GET["sec2"] = "operation/agentes/alerts_status";
break;
case 'Tactical view':
$_GET["sec"] = "estado";
$_GET["sec2"] = "operation/agentes/tactical";
break;
case 'Default':
$_GET["sec"] = "general/logon_ok";
break;
case 'Dashboard':
$_GET["sec"] = "dashboard";
$_GET["sec2"] = ENTERPRISE_DIR.'/dashboard/main_dashboard';
break;
case 'Visual console':
$_GET["sec"] = "visualc";
$_GET["sec2"] = "operation/visual_console/index";
break;
case 'Other':
$home_url = io_safe_output($home_url);
parse_str ($home_url, $res);
$_GET["sec"] = $res["sec"];
$_GET["sec2"] = $res["sec2"];
break;
}
}
else {
$_GET["sec"] = "general/logon_ok";
}
}
db_logon ($nick_in_db, $_SERVER['REMOTE_ADDR']);
$_SESSION['id_usuario'] = $nick_in_db;
$config['id_user'] = $nick_in_db;
//Remove everything that might have to do with people's passwords or logins
unset ($pass, $login_good);
$user_language = get_user_language($config['id_user']);
$l10n = NULL;
if (file_exists ('./include/languages/' . $user_language . '.mo')) {
$l10n = new gettext_reader (new CachedFileReader ('./include/languages/'.$user_language.'.mo'));
$l10n->load_tables();
}
}
else { //login wrong
$blocked = false;
if ((!is_user_admin($nick) || $config['enable_pass_policy_admin']) && defined('PANDORA_ENTERPRISE')) {
$blocked = login_check_blocked($nick);
}
if (!$blocked) {
if (defined('PANDORA_ENTERPRISE')) {
login_check_failed($nick); //Checks failed attempts
}
$login_failed = true;
require_once ('general/login_page.php');
db_pandora_audit("Logon Failed", "Invalid login: ".$nick, $nick);
while (@ob_end_flush ());
exit ("</html>");
}
else {
require_once ('general/login_page.php');
db_pandora_audit("Logon Failed", "Invalid login: ".$nick, $nick);
while (@ob_end_flush ());
exit ("</html>");
}
}
}
// Hash login process
elseif (isset ($_GET["loginhash"])) {
$loginhash_data = get_parameter("loginhash_data", "");
$loginhash_user = str_rot13(get_parameter("loginhash_user", ""));
if ($config["loginhash_pwd"] != "" && $loginhash_data == md5($loginhash_user.$config["loginhash_pwd"])) {
db_logon ($loginhash_user, $_SERVER['REMOTE_ADDR']);
$_SESSION['id_usuario'] = $loginhash_user;
$config["id_user"] = $loginhash_user;
}
else {
require_once ('general/login_page.php');
db_pandora_audit("Logon Failed", "Invalid login: ".$nick, $nick);
db_pandora_audit("Logon Failed (loginhash", "", "system");
while (@ob_end_flush ());
exit ("</html>");
}
}
}
// Hash login process
elseif (! isset ($config['id_user']) && isset ($_GET["loginhash"])) {
$loginhash_data = get_parameter("loginhash_data", "");
$loginhash_user = str_rot13(get_parameter("loginhash_user", ""));
if ($config["loginhash_pwd"] != "" && $loginhash_data == md5($loginhash_user.$config["loginhash_pwd"])) {
db_logon ($loginhash_user, $_SERVER['REMOTE_ADDR']);
$_SESSION['id_usuario'] = $loginhash_user;
$config["id_user"] = $loginhash_user;
}
// There is no user connected
else {
require_once ('general/login_page.php');
db_pandora_audit("Logon Failed (loginhash", "", "system");
while (@ob_end_flush ());
exit ("</html>");
}
}
// There is no user connected
elseif (! isset ($config['id_user'])) {
require_once ('general/login_page.php');
while (@ob_end_flush ());
exit ("</html>");
}
// Log off
if (isset ($_GET["bye"])) {

View File

@ -19,22 +19,12 @@ class User {
private $user;
private $logged = false;
private $errorLogin = false;
private $loginTime = false;
private $logout_action = false;
private $needDoubleAuth = false;
private $errorDoubleAuth = false;
public function __construct($user = null, $password = null) {
$this->user = $user;
$this->errorLogin = false;
if (process_user_login($this->user, $password)) {
$this->logged = true;
$this->hackInjectConfig();
}
else {
$this->logged = false;
}
}
public static function getInstance() {
public static function getInstance () {
if (!(self::$instance instanceof self)) {
//Check if in the session
$system = System::getInstance();
@ -51,22 +41,22 @@ class User {
return self::$instance;
}
public function hackInjectConfig() {
//hack to compatibility with pandora
public function saveLogin () {
if ($this->logged) {
global $config;
$system = System::getInstance();
$config['id_user'] = $this->user;
$system->setSessionBase('id_usuario', $this->user);
$system->setSession('user', $this);
if (!$this->needDoubleAuth) {
//hack to compatibility with pandora
global $config;
$config['id_user'] = $this->user;
$system->setSessionBase('id_usuario', $this->user);
}
}
}
public function isLogged() {
public function isLogged () {
$system = System::getInstance();
$autologin = $system->getRequest('autologin', false);
@ -74,15 +64,13 @@ class User {
$user = $system->getRequest('user', null);
$password = $system->getRequest('password', null);
if ($this->checkLogin($user, $password)) {
$this->hackInjectConfig();
}
$this->login($user, $password);
}
return $this->logged;
}
public function checkLogin($user = null, $password = null) {
public function login ($user = null, $password = null) {
$system = System::getInstance();
if (($user == null) && ($password == null)) {
@ -92,44 +80,126 @@ class User {
}
if (!empty($user) && !empty($password)) {
if (process_user_login($user, $password) !== false) {
$user_in_db = process_user_login($user, $password);
if ($user_in_db !== false) {
$this->logged = true;
$this->user = $user;
$this->user = $user_in_db;
$this->loginTime = time();
$this->errorLogin = false;
// The user login was successful, but the second step is not completed
if ($this->isDobleAuthRequired()) {
$this->needDoubleAuth = true;
}
}
else {
$this->logged = false;
$this->loginTime = false;
$this->errorLogin = true;
$this->needDoubleAuth = false;
$this->errorDoubleAuth = false;
}
}
if ($this->logged) {
$this->hackInjectConfig();
if (! check_acl($system->getConfig('id_user'), 0, "AR")) {
db_pandora_audit("ACL Violation",
"Trying to access Agent Data view");
require ("../general/noaccess.php");
return;
}
}
$this->saveLogin();
return $this->logged;
}
public function logout() {
$this->user = null;
$this->logged = false;
$this->errorLogin = false;
$this->logout_action = true;
$system = System::getInstance();
$system->setSession('user', null);
public function getLoginTime () {
return $this->loginTime;
}
public function showLogin() {
public function isWaitingDoubleAuth () {
return $this->needDoubleAuth;
}
public function isDobleAuthRequired ($user = false) {
if (empty($user) && !empty($this->user))
$user = $this->user;
if (!empty($user))
return (bool) db_get_value('id', 'tuser_double_auth', 'id_user', $user);
else
return false;
}
public function validateDoubleAuthCode ($user = null, $code = null) {
if (!$this->needDoubleAuth) {
return true;
}
$system = System::getInstance();
require_once ($system->getConfig('homedir').'/include/auth/GAuth/Auth.php');
$result = false;
if (empty($user)) {
$user = $this->user;
}
if (empty($code)) {
$code = $system->getRequest('auth_code', null);
}
if (!empty($user) && !empty($code)) {
$secret = db_get_value('secret', 'tuser_double_auth', 'id_user', $user);
if ($secret === false) {
$result = false;
$this->errorDoubleAuth = array(
'title_text' => __('Double authentication failed'),
'content_text' => __('Secret code not found') .". "
.__('Please contact the administrator to reset your double authentication')
);
}
else if (!empty($secret)) {
try {
$gAuth = new \GAuth\Auth($secret);
$result = $gAuth->validateCode($code);
// Double auth success
if ($result) {
$this->needDoubleAuth = false;
$this->saveLogin();
}
else {
$result = false;
$this->errorDoubleAuth = array(
'title_text' => __('Double authentication failed'),
'content_text' => __('Invalid code')
);
}
} catch (Exception $e) {
$result = false;
$this->errorDoubleAuth = array(
'title_text' => __('Double authentication failed'),
'content_text' => __('There was an error checking the code')
);
}
}
}
return $result;
}
public function logout () {
$this->user = null;
$this->logged = false;
$this->loginTime = false;
$this->errorLogin = false;
$this->logout_action = true;
$this->needDoubleAuth = false;
$this->errorDoubleAuth = false;
$system = System::getInstance();
$system->setSession('user', null);
$system->sessionDestroy();
}
public function showLoginPage () {
global $pandora_version;
$ui = Ui::getInstance();
@ -191,16 +261,65 @@ class User {
$this->errorLogin = false;
$this->logout_action = false;
}
public function getIdUser() {
public function showDoubleAuthPage () {
global $pandora_version;
$ui = Ui::getInstance();
$ui->createPage();
if (!empty($this->errorDoubleAuth)) {
$options['type'] = 'onStart';
$options['title_text'] = $this->errorDoubleAuth['title_text'];
$options['content_text'] = $this->errorDoubleAuth['content_text'] . "<br>";
$ui->addDialog($options);
}
$left_button = $ui->createHeaderButton(
array('icon' => 'back',
'pos' => 'left',
'text' => __('Logout'),
'href' => 'index.php?action=logout'));
$ui->createHeader('', $left_button);
$ui->showFooter(false);
$ui->beginContent();
$ui->contentAddHtml('<div style="text-align: center;" class="login_logo">' .
html_print_image ("mobile/images/pandora_mobile_console.png",
true, array ("alt" => "logo", "border" => 0)) .
'</div>');
$ui->contentAddHtml('<div id="login_container">');
$ui->beginForm();
$ui->formAddHtml(html_print_input_hidden('action', 'double_auth', true));
$options = array(
'name' => 'auth_code',
'value' => '',
'placeholder' => __('Authenticator code'),
'label' => __('Authenticator code')
);
$ui->formAddInputPassword($options);
$options = array(
'value' => __('Check code'),
'icon' => 'arrow-r',
'icon_pos' => 'right',
'name' => 'auth_code_btn'
);
$ui->formAddSubmitButton($options);
$ui->endForm();
$ui->contentAddHtml('</div>');
$ui->endContent();
$ui->showPage();
$this->errorDoubleAuth = false;
}
public function getIdUser () {
return $this->user; //Oldies methods
}
public function isInGroup($access = "AR", $id_group = 0, $name_group = false) {
public function isInGroup ($access = "AR", $id_group = 0, $name_group = false) {
return (bool)check_acl($this->user, $id_group, $access);
}
public function getIdGroups($access = "AR", $all = false) {
public function getIdGroups ($access = "AR", $all = false) {
return array_keys(users_get_groups($this->user, $access, $all));
}
}

View File

@ -43,13 +43,32 @@ $enterpriseHook = enterprise_include('mobile/operation/home.php');
$system = System::getInstance();
require_once($system->getConfig('homedir').'/include/constants.php');
$user = User::getInstance();
$user->hackInjectConfig();
$user->saveLogin();
$page = $system->getRequest('page', 'home');
$action = $system->getRequest('action');
if (!$user->isLogged()) {
$action = 'login';
// The logout action has priority
if ($action != 'logout') {
if (!$user->isLogged()) {
$action = 'login';
}
else if ($user->isWaitingDoubleAuth()) {
$dauth_period = SECONDS_2MINUTES;
$now = time();
$dauth_time = $user->getLoginTime();
if ($now - $dauth_period < $dauth_time) {
$action = 'double_auth';
}
// Expired login
else {
$action = 'logout';
}
}
}
if ($action != "ajax") {
@ -107,11 +126,45 @@ switch ($action) {
return;
break;
case 'login':
if (!$user->checkLogin()) {
$user->showLogin();
if ($user->login() && $user->isLogged()) {
if ($user->isWaitingDoubleAuth()) {
if ($user->validateDoubleAuthCode()) {
$user_language = get_user_language ($system->getConfig('id_user'));
if (file_exists ('../include/languages/'.$user_language.'.mo')) {
$l10n = new gettext_reader (new CachedFileReader('../include/languages/'.$user_language.'.mo'));
$l10n->load_tables();
}
if (class_exists("HomeEnterprise"))
$home = new HomeEnterprise();
else
$home = new Home();
$home->show();
}
else {
$user->showDoubleAuthPage();
}
}
else {
$user_language = get_user_language ($system->getConfig('id_user'));
if (file_exists ('../include/languages/'.$user_language.'.mo')) {
$l10n = new gettext_reader (new CachedFileReader('../include/languages/'.$user_language.'.mo'));
$l10n->load_tables();
}
if (class_exists("HomeEnterprise"))
$home = new HomeEnterprise();
else
$home = new Home();
$home->show();
}
}
else {
if ($user->isLogged()) {
$user->showLoginPage();
}
break;
case 'double_auth':
if ($user->isLogged()) {
if ($user->validateDoubleAuthCode()) {
$user_language = get_user_language ($system->getConfig('id_user'));
if (file_exists ('../include/languages/'.$user_language.'.mo')) {
$l10n = new gettext_reader (new CachedFileReader('../include/languages/'.$user_language.'.mo'));
@ -124,13 +177,16 @@ switch ($action) {
$home->show();
}
else {
$user->showLoginFail();
$user->showDoubleAuthPage();
}
}
else {
$user->showLoginPage();
}
break;
case 'logout':
$user->logout();
$user->showLogin();
$user->showLoginPage();
break;
default:
if (class_exists("Enterprise")) {

View File

@ -337,6 +337,23 @@ if (!$meta) {
$table->data[] = $data;
}
// Double auth
$double_auth_enabled = (bool) db_get_value('id', 'tuser_double_auth', 'id_user', $config['id_user']);
$data = array();
$data[0] = __('Double authentication');
$data[0] .= '<br>';
$data[0] .= html_print_checkbox('double_auth', 1, $double_auth_enabled, true);
if ($double_auth_enabled) {
$data[0] .= '&nbsp;&nbsp;';
$data[0] .= html_print_button(__('Show information'), 'show_info', false, 'javascript:show_double_auth_info();', '', true);
}
// Dialog
$data[0] .= "<div id=\"dialog-double_auth\"><div id=\"dialog-double_auth-container\"></div></div>";
$table->colspan[count($table->data)][0] = 3;
$table->rowclass[] = '';
$table->rowstyle[] = 'font-weight: bold;';
$table->data[] = $data;
$data = array();
$data[0] = __('Comments');
$table->colspan[count($table->data)][0] = 3;
@ -431,6 +448,17 @@ $(document).ready (function () {
$("#text-block_size").removeAttr('disabled');
}
}
$("input#checkbox-double_auth").change(function (e) {
e.preventDefault();
if (this.checked) {
show_double_auth_activation();
}
else {
show_double_auth_deactivation();
}
});
show_data_section();
});
@ -481,4 +509,209 @@ function show_data_section () {
break;
}
}
function show_double_auth_info () {
var userID = "<?php echo $config['id_user']; ?>";
var $loadingSpinner = $("<img src=\"<?php echo $config['homeurl']; ?>/images/spinner.gif\" />");
var $dialogContainer = $("div#dialog-double_auth-container");
$dialogContainer.html($loadingSpinner);
// Load the info page
var request = $.ajax({
url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",
type: 'POST',
dataType: 'html',
data: {
page: 'include/ajax/double_auth.ajax',
id_user: userID,
get_double_auth_data_page: 1,
containerID: $dialogContainer.prop('id')
},
complete: function(xhr, textStatus) {
},
success: function(data, textStatus, xhr) {
// isNaN = is not a number
if (isNaN(data)) {
$dialogContainer.html(data);
}
// data is a number, convert it to integer to do the compare
else if (Number(data) === -1) {
$dialogContainer.html("<?php echo '<b><div class=\"red\">' . __('Authentication error') . '</div></b>'; ?>");
}
else {
$dialogContainer.html("<?php echo '<b><div class=\"red\">' . __('Error') . '</div></b>'; ?>");
}
},
error: function(xhr, textStatus, errorThrown) {
$dialogContainer.html("<?php echo '<b><div class=\"red\">' . __('There was an error loading the data') . '</div></b>'; ?>");
}
});
$("div#dialog-double_auth")
.append($dialogContainer)
.dialog({
resizable: true,
draggable: true,
modal: true,
title: "<?php echo __('Double autentication information'); ?>",
overlay: {
opacity: 0.5,
background: "black"
},
width: 400,
height: 375,
close: function(event, ui) {
// Abort the ajax request
if (typeof request != 'undefined')
request.abort();
// Remove the contained html
$dialogContainer.empty();
}
})
.show();
}
function show_double_auth_activation () {
var userID = "<?php echo $config['id_user']; ?>";
var $loadingSpinner = $("<img src=\"<?php echo $config['homeurl']; ?>/images/spinner.gif\" />");
var $dialogContainer = $("div#dialog-double_auth-container");
$dialogContainer.html($loadingSpinner);
// Load the info page
var request = $.ajax({
url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",
type: 'POST',
dataType: 'html',
data: {
page: 'include/ajax/double_auth.ajax',
id_user: userID,
get_double_auth_info_page: 1,
containerID: $dialogContainer.prop('id')
},
complete: function(xhr, textStatus) {
},
success: function(data, textStatus, xhr) {
// isNaN = is not a number
if (isNaN(data)) {
$dialogContainer.html(data);
}
// data is a number, convert it to integer to do the compare
else if (Number(data) === -1) {
$dialogContainer.html("<?php echo '<b><div class=\"red\">' . __('Authentication error') . '</div></b>'; ?>");
}
else {
$dialogContainer.html("<?php echo '<b><div class=\"red\">' . __('Error') . '</div></b>'; ?>");
}
},
error: function(xhr, textStatus, errorThrown) {
$dialogContainer.html("<?php echo '<b><div class=\"red\">' . __('There was an error loading the data') . '</div></b>'; ?>");
}
});
$("div#dialog-double_auth").dialog({
resizable: true,
draggable: true,
modal: true,
title: "<?php echo __('Double autentication activation'); ?>",
overlay: {
opacity: 0.5,
background: "black"
},
width: 500,
height: 400,
close: function(event, ui) {
// Abort the ajax request
if (typeof request != 'undefined')
request.abort();
// Remove the contained html
$dialogContainer.empty();
document.location.reload();
}
})
.show();
}
function show_double_auth_deactivation () {
var userID = "<?php echo $config['id_user']; ?>";
var $loadingSpinner = $("<img src=\"<?php echo $config['homeurl']; ?>/images/spinner.gif\" />");
var $dialogContainer = $("div#dialog-double_auth-container");
var message = "<p><?php echo __('Are you sure?') . '<br>' . __('The double authentication will be deactivated'); ?></p>";
var $button = $("<input type=\"button\" value=\"<?php echo __('Deactivate'); ?>\" />");
$dialogContainer
.empty()
.append(message)
.append($button);
var request;
$button.click(function(e) {
e.preventDefault();
$dialogContainer.html($loadingSpinner);
// Deactivate the double auth
request = $.ajax({
url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",
type: 'POST',
dataType: 'json',
data: {
page: 'include/ajax/double_auth.ajax',
id_user: userID,
deactivate_double_auth: 1
},
complete: function(xhr, textStatus) {
},
success: function(data, textStatus, xhr) {
if (data === -1) {
$dialogContainer.html("<?php echo '<b><div class=\"red\">' . __('Authentication error') . '</div></b>'; ?>");
}
else if (data) {
$dialogContainer.html("<?php echo '<b><div class=\"green\">' . __('The double autentication was deactivated successfully') . '</div></b>'; ?>");
}
else {
$dialogContainer.html("<?php echo '<b><div class=\"red\">' . __('There was an error deactivating the double autentication') . '</div></b>'; ?>");
}
},
error: function(xhr, textStatus, errorThrown) {
$dialogContainer.html("<?php echo '<b><div class=\"red\">' . __('There was an error deactivating the double autentication') . '</div></b>'; ?>");
}
});
});
$("div#dialog-double_auth").dialog({
resizable: true,
draggable: true,
modal: true,
title: "<?php echo __('Double autentication activation'); ?>",
overlay: {
opacity: 0.5,
background: "black"
},
width: 300,
height: 150,
close: function(event, ui) {
// Abort the ajax request
if (typeof request != 'undefined')
request.abort();
// Remove the contained html
$dialogContainer.empty();
document.location.reload();
}
})
.show();
}
</script>

View File

@ -1047,6 +1047,17 @@ CREATE TABLE tusuario_perfil (
CREATE SEQUENCE tusuario_perfil_s INCREMENT BY 1 START WITH 1;
CREATE OR REPLACE TRIGGER tusuario_perfil_inc BEFORE INSERT ON tusuario_perfil REFERENCING NEW AS NEW FOR EACH ROW BEGIN SELECT tusuario_perfil_s.nextval INTO :NEW.ID_UP FROM dual; END tusuario_perfil_inc;;
-- ----------------------------------------------------------------------
-- Table `tuser_double_auth`
-- ----------------------------------------------------------------------
CREATE TABLE tuser_double_auth (
id NUMBER(10, 0) NOT NULL PRIMARY KEY,
id_user VARCHAR2(60) NOT NULL REFERENCES tusuario(id_user) ON DELETE CASCADE,
secret VARCHAR2(20) NOT NULL
);
CREATE SEQUENCE tuser_double_auth_s INCREMENT BY 1 START WITH 1;
CREATE OR REPLACE TRIGGER tuser_double_auth_inc BEFORE INSERT ON tuser_double_auth REFERENCING NEW AS NEW FOR EACH ROW BEGIN SELECT tuser_double_auth_s.nextval INTO :NEW.ID FROM dual; END tuser_double_auth_inc;;
-- ---------------------------------------------------------------------
-- Table "tnews"
-- ---------------------------------------------------------------------

View File

@ -926,6 +926,15 @@ CREATE TABLE "tusuario_perfil" (
"tags" text NOT NULL
);
-- ----------------------------------------------------------------------
-- Table `tuser_double_auth`
-- ----------------------------------------------------------------------
CREATE TABLE "tuser_double_auth" (
"id" SERIAL NOT NULL PRIMARY KEY,
"id_user" varchar(60) NOT NULL UNIQUE REFERENCES "tusuario"("id_user") ON DELETE CASCADE,
"secret" varchar(20) NOT NULL
);
-- -----------------------------------------------------
-- Table `tnews`
-- -----------------------------------------------------

View File

@ -999,6 +999,18 @@ CREATE TABLE IF NOT EXISTS `tusuario_perfil` (
PRIMARY KEY (`id_up`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- Table `tuser_double_auth`
-- ----------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `tuser_double_auth` (
`id` int(10) unsigned NOT NULL auto_increment,
`id_user` varchar(60) NOT NULL,
`secret` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE (`id_user`),
FOREIGN KEY (`id_user`) REFERENCES tusuario(`id_user`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- Table `tnews`
-- ----------------------------------------------------------------------

View File

@ -154,6 +154,7 @@ sub help_screen{
help_screen_line('--add_profile_to_user', '<user_id> <profile_name> [<group_name>]', 'Add a profile in group to a user');
help_screen_line('--disable_eacl', '', 'Disable enterprise ACL system');
help_screen_line('--enable_eacl', '', 'Enable enterprise ACL system');
help_screen_line('--disable_double_auth', '<user_name>', 'Disable the double authentication for the specified user');
print "\nEVENTS:\n\n" unless $param ne '';
help_screen_line('--create_event', "<event> <event_type> <group_name> [<agent_name> <module_name>\n\t <event_status> <severity> <template_name> <user_name> <comment> \n\t <source> <id_extra> <tags> <custom_data_json>]", 'Add event');
help_screen_line('--validate_event', "<agent_name> <module_name> <datetime_min> <datetime_max>\n\t <user_name> <criticity> <template_name>", 'Validate events');
@ -3362,6 +3363,23 @@ sub cli_enable_eacl ($$) {
exit;
}
###############################################################################
# Disable double authentication
# Related option: --disable_double_auth
###############################################################################
sub cli_disable_double_auth () {
my $user_id = @ARGV[2];
print_log "[INFO] Disabling double authentication for the user '$user_id'\n\n";
$user_id = safe_input($user_id);
# Delete the user secret
my $result = db_do ($dbh, 'DELETE FROM tuser_double_auth WHERE id_user = ?', $user_id);
exit;
}
###############################################################################
# Enable user
# Related option: --enable_user
@ -3691,21 +3709,25 @@ sub pandora_manage_main ($$$) {
}
elsif ($param eq '--disable_alerts') {
param_check($ltotal, 0);
cli_disable_alerts ($conf, $dbh);
}
cli_disable_alerts ($conf, $dbh);
}
elsif ($param eq '--enable_alerts') {
param_check($ltotal, 0);
cli_enable_alerts ($conf, $dbh);
}
cli_enable_alerts ($conf, $dbh);
}
elsif ($param eq '--disable_eacl') {
param_check($ltotal, 0);
cli_disable_eacl ($conf, $dbh);
}
cli_disable_eacl ($conf, $dbh);
}
elsif ($param eq '--enable_eacl') {
param_check($ltotal, 0);
cli_enable_eacl ($conf, $dbh);
}
elsif ($param eq '--disable_group') {
cli_enable_eacl ($conf, $dbh);
}
elsif ($param eq '--disable_double_auth') {
param_check($ltotal, 1);
cli_disable_double_auth();
}
elsif ($param eq '--disable_group') {
param_check($ltotal, 1);
cli_disable_group();
}