Skip to content

Commit 7a296d5

Browse files
author
Kristan Kenney
committed
Add new login screen to fix branch due to error log flood issue
This fix has been fast tracked to ship with v1.2.1 due to an issue where entry to the login screen causes high CPU load and spamming in the error log due to an error in 2FA checks. Login screen has been redesigned as a multi-step process (Username > Password > 2FA Token) to better validate entry.
2 parents 1ab520d + ba6c51b commit 7a296d5

File tree

8 files changed

+213
-133
lines changed

8 files changed

+213
-133
lines changed

web/login/index.php

Lines changed: 74 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
define('NO_AUTH_REQUIRED',true);
44

5-
65
// Main include
76
include($_SERVER['DOCUMENT_ROOT']."/inc/main.php");
87

9-
10-
$TAB = 'LOGIN';
8+
$TAB = 'login';
119

1210
// Logout
1311
if (isset($_GET['logout'])) {
1412
session_destroy();
1513
}
1614

15+
16+
1717
// Login as someone else
1818
if (isset($_SESSION['user'])) {
1919
if ($_SESSION['user'] == 'admin' && !empty($_GET['loginas'])) {
@@ -33,27 +33,25 @@
3333
exit;
3434
}
3535

36-
// Basic auth
37-
if (isset($_POST['user']) && isset($_POST['password'])) {
36+
function authenticate_user(){
3837
if(isset($_SESSION['token']) && isset($_POST['token']) && $_POST['token'] == $_SESSION['token']) {
39-
$v_user = escapeshellarg($_POST['user']);
40-
$v_ip = escapeshellarg($_SERVER['REMOTE_ADDR']);
41-
if(isset($_SERVER['HTTP_CF_CONNECTING_IP'])){
42-
if(!empty($_SERVER['HTTP_CF_CONNECTING_IP'])){
43-
$v_ip = escapeshellarg($_SERVER['HTTP_CF_CONNECTING_IP']);
44-
}
38+
$v_user = escapeshellarg($_POST['user']);
39+
$v_ip = escapeshellarg($_SERVER['REMOTE_ADDR']);
40+
if(isset($_SERVER['HTTP_CF_CONNECTING_IP'])){
41+
if(!empty($_SERVER['HTTP_CF_CONNECTING_IP'])){
42+
$v_ip = escapeshellarg($_SERVER['HTTP_CF_CONNECTING_IP']);
4543
}
46-
if (isset($_POST['twofa'])) {
47-
$v_twofa = escapeshellarg($_POST['twofa']);
48-
}
49-
50-
// Get user's salt
51-
$output = '';
52-
exec (HESTIA_CMD."v-get-user-salt ".$v_user." ".$v_ip." json" , $output, $return_var);
53-
$pam = json_decode(implode('', $output), true);
54-
if ( $return_var > 0 ) {
55-
sleep(5);
56-
$ERROR = "<a class=\"error\">".__('Invalid username or password')."</a>";
44+
}
45+
// Get user's salt
46+
$output = '';
47+
exec (HESTIA_CMD."v-get-user-salt ".$v_user." ".$v_ip." json" , $output, $return_var);
48+
$pam = json_decode(implode('', $output), true);
49+
if ( $return_var > 0 ) {
50+
sleep(2);
51+
unset($_POST['password']);
52+
unset($_POST['user']);
53+
$error = "<a class=\"error\">".__('Invalid username or password')."</a>";
54+
return $error;
5755
} else {
5856
$user = $_POST['user'];
5957
$password = $_POST['password'];
@@ -86,8 +84,10 @@
8684

8785
// Check API answer
8886
if ( $return_var > 0 ) {
89-
sleep(5);
90-
$ERROR = "<a class=\"error\">".__('Invalid username or password')."</a>";
87+
sleep(2);
88+
unset($_POST['password']);
89+
$error = "<a class=\"error\">".__('Invalid username or password')."</a>";
90+
return $error;
9191
} else {
9292

9393
// Make root admin user
@@ -99,64 +99,60 @@
9999

100100
// Check if 2FA is active
101101
if ($data[$_POST['user']]['TWOFA'] != '') {
102-
if (isset($v_twofa)){
103-
$v_twofa = str_replace(' ', '', $v_twofa);
102+
if (empty($_POST['twofa'])){
103+
return false;
104+
}else{
105+
$v_twofa = $_POST['twofa'];
104106
exec(HESTIA_CMD ."v-check-user-2fa ".$v_user." ".$v_twofa, $output, $return_var);
105107
unset($output);
106108
if ( $return_var > 0 ) {
107-
sleep(1);
108-
$ERROR = "<a class=\"error\">".__('Invalid or missing 2FA token')."</a>";
109+
sleep(2);
110+
$error = "<a class=\"error\">".__('Invalid or missing 2FA token')."</a>";
111+
return $error;
112+
unset($_POST['twofa']);
109113
}
110-
} else {
111-
sleep(1);
112-
$ERROR = "<a class=\"error\">".__('Invalid or missing 2FA token')."</a>";
113-
}
114+
}
115+
}
116+
// Define session user
117+
$_SESSION['user'] = key($data);
118+
$v_user = $_SESSION['user'];
119+
120+
// Define language
121+
$output = '';
122+
exec (HESTIA_CMD."v-list-sys-languages json", $output, $return_var);
123+
$languages = json_decode(implode('', $output), true);
124+
if (in_array($data[$v_user]['LANGUAGE'], $languages)){
125+
$_SESSION['language'] = $data[$v_user]['LANGUAGE'];
126+
} else {
127+
$_SESSION['language'] = 'en';
114128
}
115129

116-
// Check if 2FA was successfully
117-
if ( ! isset($v_twofa) || $ERROR == '' ) {
118-
// Define session user
119-
$_SESSION['user'] = key($data);
120-
$v_user = $_SESSION['user'];
121-
122-
// Get user favorites
123-
get_favourites();
124-
125-
// Define language
126-
$output = '';
127-
exec (HESTIA_CMD."v-list-sys-languages json", $output, $return_var);
128-
$languages = json_decode(implode('', $output), true);
129-
if (in_array($data[$v_user]['LANGUAGE'], $languages)){
130-
$_SESSION['language'] = $data[$v_user]['LANGUAGE'];
131-
} else {
132-
$_SESSION['language'] = 'en';
133-
}
134-
135-
// Regenerate session id to prevent session fixation
136-
session_regenerate_id();
137-
138-
// Redirect request to control panel interface
139-
if (!empty($_SESSION['request_uri'])) {
140-
header("Location: ".$_SESSION['request_uri']);
141-
unset($_SESSION['request_uri']);
142-
exit;
130+
// Regenerate session id to prevent session fixation
131+
session_regenerate_id();
132+
133+
// Redirect request to control panel interface
134+
if (!empty($_SESSION['request_uri'])) {
135+
header("Location: ".$_SESSION['request_uri']);
136+
unset($_SESSION['request_uri']);
137+
exit;
138+
} else {
139+
if ($v_user == 'admin') {
140+
header("Location: /list/user/");
143141
} else {
144-
if ($v_user == 'admin') {
145-
header("Location: /list/user/");
146-
} else {
147-
header("Location: /list/web/");
148-
}
149-
exit;
142+
header("Location: /list/web/");
150143
}
144+
exit;
151145
}
152146
}
153147
}
154-
} else {
155-
sleep(1);
156-
$ERROR = "<a class=\"error\">".__('Invalid or missing token')."</a>";
157148
}
158149
}
159150

151+
if (!empty($_POST['user']) && !empty($_POST['password']) && !empty($_POST['twofa'])){
152+
$error = authenticate_user();
153+
} else if (!empty($_POST['user']) && !empty($_POST['password'])) {
154+
$error = authenticate_user();
155+
}
160156
// Check system configuration
161157
load_hestia_config();
162158

@@ -180,7 +176,15 @@
180176

181177
// Generate CSRF token
182178
$_SESSION['token'] = md5(uniqid(mt_rand(), true));
183-
184179
require_once($_SERVER['DOCUMENT_ROOT'].'/inc/i18n/'.$_SESSION['language'].'.php');
185180
require_once('../templates/header.html');
186-
require_once('../templates/login.html');
181+
if (empty($_POST['user'])) {
182+
require_once('../templates/login.html');
183+
}else if (empty($_POST['password'])) {
184+
require_once('../templates/login_1.html');
185+
}else if (empty($_POST['twofa'])) {
186+
require_once('../templates/login_2.html');
187+
} else {
188+
require_once('../templates/login.html');
189+
}
190+
?>

web/templates/login.html

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -17,52 +17,22 @@
1717
</td>
1818
</tr>
1919
<tr>
20-
<td style="padding: 12px 0 0 2px;">
20+
<td style="padding: 12px 0 5px 2px;">
2121
<?php print __('Username');?>
2222
</td>
2323
</tr>
2424
<tr>
2525
<td>
26-
<input tabindex="1" type="text" size="20px" style="width:240px;" name="user" class="vst-input">
26+
<input tabindex="1" type="text" size="20px" style="width:240px;" name="user" class="vst-input" autofocus />
2727
</td>
2828
</tr>
2929
<tr>
30-
<td style="padding: 12px 0 0 2px;">
31-
<?php print __('Password');?>
32-
<div style="padding:0 6px 0px 14px; float:right;">
33-
<a tabindex="5" class="vst-advanced" href="/reset/">
34-
<?php print __('forgot password');?>
35-
</a>
36-
</div>
30+
<td height="10px">
3731
</td>
3832
</tr>
3933
<tr>
40-
<td>
41-
<input tabindex="2" type="password" size="20px" style="width:240px;" name="password" class="vst-input">
42-
</td>
43-
</tr>
44-
<tr class="twofa" style="display:none;">
45-
<td style="padding-top: 12px; padding-left:2px;">
46-
<?php print __('2FA Token');?>
47-
<div style="padding:0 6px 0px 14px; float:right;">
48-
<a tabindex="5" class="vst-advanced" href="/reset2fa/">
49-
<?php print __('Forgot token');?>
50-
</a>
51-
</div>
52-
</td>
53-
</tr>
54-
<tr class="twofa" style="display:none;">
55-
<td>
56-
<input tabindex="3" type="text" size="20px" style="width:240px;" name="twofa" class="vst-input">
57-
</td>
58-
</tr>
59-
<tr>
60-
<td height="28px">
61-
</td>
62-
</tr>
63-
<tr>
64-
<td style="padding: 0 0 12px 0;">
65-
<button tabindex="3" type="submit" class="button"><?php print __('Log in');?>&nbsp;&nbsp;&nbsp;<i class="fas fa-sign-in-alt"></i></button>
34+
<td style="padding: 0 0 5px 0;">
35+
<button tabindex="3" type="submit" class="button"><?php print __('Next');?>&nbsp;&nbsp;&nbsp;<i class="fas fa-sign-in-alt"></i></button>
6636
</td>
6737
</tr>
6838
</table>
@@ -72,31 +42,14 @@
7242
<tr>
7343
<td colspan=2>
7444
<div class="login-bottom">
75-
<div style="height:20px"><?php if (isset($ERROR)) echo $ERROR ?></div>
45+
<div style="height:20px"><?php if (isset($error)) echo $error ?></div>
7646
</div>
7747
</td>
7848
</tr>
7949
</table>
8050
</tr>
8151
</table>
8252
</center>
83-
<script type="text/javascript">
84-
$(document).ready(function () {
85-
$('#form_login').on('input', 'input[name="user"]', function() {
86-
var username = this.value;
87-
$.ajax({
88-
type: 'GET',
89-
url: '/inc/2fa/active.php?user=' + username,
90-
complete: function(xhr) {
91-
if(xhr.status == '200'){
92-
$('.twofa').show();
93-
}else if(xhr.status == '404'){
94-
$('.twofa').hide();
95-
}
96-
}
97-
});
98-
});
99-
});
100-
</script>
53+
10154
</body>
102-
</html>
55+
</html>

web/templates/login_1.html

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<center>
2+
<table class="login">
3+
<tr>
4+
<td>
5+
<table>
6+
<tr>
7+
<td style="padding: 22px 30px 0 42px; height: 280px; width: 170px;">
8+
<a href="/"><img border=0 src="/images/logo.png" alt="<?=__('Hestia Control Panel');?>" style="margin: 20px; margin-top: 64px;" /></a>
9+
</td>
10+
<td style="padding: 40px 60px 0 0;" class="animated fadeIn">
11+
<form method="post" action="/login/" id="form_login">
12+
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
13+
<input type="hidden" name="user" value="<?php echo $_POST['user']; ?>">
14+
15+
<table class="login-box">
16+
<tr>
17+
<td style="padding: 12px 0 0 2px;" class="login-welcome">
18+
<?php print __('Welcome');?> <?php echo $_POST['user']; ?>!
19+
</td>
20+
</tr>
21+
<tr>
22+
<td style="padding: 12px 0 0 2px;">
23+
<?php print __('Password');?>
24+
<div style="padding:0 6px 0px 14px; float:right;">
25+
<a tabindex="5" class="vst-advanced" href="/reset/">
26+
<?php print __('forgot password');?>
27+
</a>
28+
</div>
29+
</td>
30+
</tr>
31+
<tr>
32+
<td>
33+
<input tabindex="2" type="password" size="20px" style="width:240px;" name="password" class="vst-input" autofocus />
34+
</td>
35+
</tr>
36+
<tr>
37+
<td height="10px">
38+
</td>
39+
</tr>
40+
<tr>
41+
<td style="padding: 0 0 5px 0;">
42+
<button tabindex="3" type="submit" class="button"><?php print __('Login');?>&nbsp;&nbsp;&nbsp;<i class="fas fa-sign-in-alt"></i></button>&nbsp;&nbsp;
43+
<input type="button" class="button cancel" value="<?php print __('Back');?>" onclick="location.href='/login/'">
44+
</td>
45+
</tr>
46+
</table>
47+
</form>
48+
</td>
49+
</tr>
50+
<tr>
51+
<td colspan=2>
52+
<div class="login-bottom">
53+
<div style="height:20px"><?php if (isset($ERROR)) echo $ERROR ?></div>
54+
</div>
55+
</td>
56+
</tr>
57+
</table>
58+
</tr>
59+
</table>
60+
</center>
61+
</body>
62+
</html>

0 commit comments

Comments
 (0)