diff --git a/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.mysql.sql b/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.mysql.sql
index 1528f6df0b..4130bdbb4b 100755
--- a/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.mysql.sql
+++ b/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.mysql.sql
@@ -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;
diff --git a/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.oracle.sql b/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.oracle.sql
index 078ad51c72..6cd60011d4 100755
--- a/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.oracle.sql
+++ b/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.oracle.sql
@@ -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;
\ No newline at end of file
+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;;
diff --git a/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.postgreSQL.sql b/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.postgreSQL.sql
index d72ddf4e85..851a739872 100755
--- a/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.postgreSQL.sql
+++ b/pandora_console/extras/pandoradb_migrate_5.1_to_6.0.postgreSQL.sql
@@ -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;
\ No newline at end of file
+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
+);
diff --git a/pandora_console/general/login_page.php b/pandora_console/general/login_page.php
index 1e18e4e005..e126d9268d 100644
--- a/pandora_console/general/login_page.php
+++ b/pandora_console/general/login_page.php
@@ -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>';
diff --git a/pandora_console/godmode/setup/setup_auth.php b/pandora_console/godmode/setup/setup_auth.php
index 2c29c91633..1a077e1542 100644
--- a/pandora_console/godmode/setup/setup_auth.php
+++ b/pandora_console/godmode/setup/setup_auth.php
@@ -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);
diff --git a/pandora_console/include/ajax/double_auth.ajax.php b/pandora_console/include/ajax/double_auth.ajax.php
new file mode 100644
index 0000000000..642ceb778a
--- /dev/null
+++ b/pandora_console/include/ajax/double_auth.ajax.php
@@ -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;
+?>
\ No newline at end of file
diff --git a/pandora_console/include/auth/GAuth/Auth.php b/pandora_console/include/auth/GAuth/Auth.php
new file mode 100644
index 0000000000..2aa859238d
--- /dev/null
+++ b/pandora_console/include/auth/GAuth/Auth.php
@@ -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;
+	}
+}
\ No newline at end of file
diff --git a/pandora_console/include/functions.php b/pandora_console/include/functions.php
index bd2479ae65..46063ff02b 100644
--- a/pandora_console/include/functions.php
+++ b/pandora_console/include/functions.php
@@ -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;
+}
 ?>
diff --git a/pandora_console/include/functions_config.php b/pandora_console/include/functions_config.php
index 4d87e9b815..daf12e9367 100644
--- a/pandora_console/include/functions_config.php
+++ b/pandora_console/include/functions_config.php
@@ -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':
diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css
index 3bff4851e5..596da5ec98 100755
--- a/pandora_console/include/styles/pandora.css
+++ b/pandora_console/include/styles/pandora.css
@@ -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;
+}
\ No newline at end of file
diff --git a/pandora_console/index.php b/pandora_console/index.php
index d054197723..335b283dc9 100755
--- a/pandora_console/index.php
+++ b/pandora_console/index.php
@@ -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"])) {
diff --git a/pandora_console/mobile/include/user.class.php b/pandora_console/mobile/include/user.class.php
index b79818e5c1..50da3360ea 100644
--- a/pandora_console/mobile/include/user.class.php
+++ b/pandora_console/mobile/include/user.class.php
@@ -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));
 	}
 }
diff --git a/pandora_console/mobile/index.php b/pandora_console/mobile/index.php
index a2fe7a5e3f..7a7f5c0414 100644
--- a/pandora_console/mobile/index.php
+++ b/pandora_console/mobile/index.php
@@ -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")) {
diff --git a/pandora_console/operation/users/user_edit.php b/pandora_console/operation/users/user_edit.php
index ca2858d378..c3fa1f11b9 100644
--- a/pandora_console/operation/users/user_edit.php
+++ b/pandora_console/operation/users/user_edit.php
@@ -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>
diff --git a/pandora_console/pandoradb.oracle.sql b/pandora_console/pandoradb.oracle.sql
index 21d395fa01..9ddfa74875 100755
--- a/pandora_console/pandoradb.oracle.sql
+++ b/pandora_console/pandoradb.oracle.sql
@@ -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"
 -- ---------------------------------------------------------------------
diff --git a/pandora_console/pandoradb.postgreSQL.sql b/pandora_console/pandoradb.postgreSQL.sql
index 384577eb55..2b51a3f349 100755
--- a/pandora_console/pandoradb.postgreSQL.sql
+++ b/pandora_console/pandoradb.postgreSQL.sql
@@ -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`
 -- -----------------------------------------------------
diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql
index df55a2711a..3b5ae82d42 100755
--- a/pandora_console/pandoradb.sql
+++ b/pandora_console/pandoradb.sql
@@ -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`
 -- ----------------------------------------------------------------------
diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl
index faa45695aa..750bdfc9d2 100644
--- a/pandora_server/util/pandora_manage.pl
+++ b/pandora_server/util/pandora_manage.pl
@@ -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();
 		}