Skip to content

Commit 2d977bc

Browse files
authored
Implement ACL login (#218)
* Implement ACL login * Make password form optional
1 parent 6912a1d commit 2d977bc

File tree

6 files changed

+138
-10
lines changed

6 files changed

+138
-10
lines changed

includes/common.inc.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@
148148
}
149149
}
150150

151+
if (!isset($config['login']) && !empty($config['login_as_acl_auth'])) {
152+
require_once PHPREDIS_ADMIN_PATH . '/includes/login_acl.inc.php';
153+
}
151154

152155
if ($server['db'] != 0) {
153156
if (!$redis->select($server['db'])) {

includes/config.sample.inc.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@
6161
)
6262
),*/
6363

64+
// Uncomment to enable login as ACL authentication (won't work if 'login' or 'auth' is also used)
65+
// Only support using one server at this moment.
66+
// If you set the default user off, browsers will be redirected to login page.
67+
// The user and password will be stored in browser as plaintext so using HTTPS is strongly recommended.
68+
// 'login_as_acl_auth' => true,
69+
6470
// Use HTML form/cookie-based auth instead of HTTP Basic/Digest auth
6571
'cookie_auth' => false,
6672

includes/login_acl.inc.php

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
function authCheck($login)
4+
{
5+
global $redis;
6+
7+
try {
8+
$redis->auth($login['username'], $login['password']);
9+
} catch (Predis\Response\ServerException $exception) {
10+
return false;
11+
}
12+
return true;
13+
}
14+
15+
// This fill will perform HTTP basic authentication. The authentication data will be sent and stored as plaintext
16+
// Please make sure to use HTTPS proxy such as Apache or Nginx to prevent traffic eavesdropping.
17+
function authHttpBasic()
18+
{
19+
$realm = 'phpRedisAdmin';
20+
21+
if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
22+
try {
23+
global $redis;
24+
$redis->ping();
25+
} catch (Predis\Response\ServerException $exception) {
26+
header('HTTP/1.1 401 Unauthorized');
27+
header('WWW-Authenticate: Basic realm="' . $realm . '"');
28+
die('NOAUTH -- Authentication required');
29+
}
30+
}
31+
32+
$login = [
33+
'username' => $_SERVER['PHP_AUTH_USER'],
34+
'password' => $_SERVER['PHP_AUTH_PW'],
35+
];
36+
37+
if (!authCheck($login)) {
38+
header('HTTP/1.1 401 Unauthorized');
39+
header('WWW-Authenticate: Basic realm="' . $realm . '"');
40+
die('NOAUTH -- Authentication required');
41+
}
42+
43+
return $login;
44+
}
45+
46+
// Perform auth using a standard HTML <form> submission and cookies to save login state
47+
function authCookie()
48+
{
49+
if (!empty($_COOKIE['phpRedisAdminLogin'])) {
50+
// We have a cookie; is it correct?
51+
// Cookie value looks like "username:password-hash"
52+
$login = explode(':', $_COOKIE['phpRedisAdminLogin'], 2);
53+
if (count($login) === 2) {
54+
$login = [
55+
'username' => $login[0],
56+
'password' => $login[1],
57+
];
58+
if (authCheck($login)) {
59+
return $login;
60+
}
61+
}
62+
}
63+
64+
if (isset($_POST['username'], $_POST['password'])) {
65+
// Login form submitted; correctly?
66+
$login = [
67+
'username' => $_POST['username'],
68+
'password' => $_POST['password'],
69+
];
70+
71+
if (authCheck($login)) {
72+
setcookie('phpRedisAdminLogin', $login['username'] . ':' . $login['password']);
73+
// This should be an absolute URL, but that's a bit of a pain to generate; this will work
74+
header("Location: index.php");
75+
die();
76+
}
77+
}
78+
79+
try {
80+
global $redis;
81+
$redis->ping();
82+
} catch (Predis\Response\ServerException $exception) {
83+
// If we're here, we don't have a valid login cookie and we don't have a
84+
// valid form submission, so redirect to the login page if we aren't
85+
// already on that page
86+
if (!defined('LOGIN_PAGE')) {
87+
header("Location: login.php");
88+
die();
89+
}
90+
}
91+
92+
// We must be on the login page without a valid cookie or submission
93+
return null;
94+
}
95+
96+
if (!empty($config['cookie_auth'])) {
97+
$login = authCookie();
98+
} else {
99+
$login = authHttpBasic();
100+
}

login.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
<label for="inputPassword" class="sr-only">Password</label>
3434
<input type="password" name="password" id="inputPassword" class="form-control"
3535
placeholder="Password"
36-
required <?= isset($_POST['username']) ? 'autofocus' : '' ?>>
36+
<?= isset($_POST['username']) ? 'autofocus' : '' ?>>
3737

3838
<button class="btn btn-lg btn-primary btn-block" type="submit">Log in</button>
3939
</form>

logout.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
setcookie('phpRedisAdminLogin', '', 1);
99
header("Location: login.php");
1010
die();
11+
} else if (isset($config['login_as_acl_auth'])) {
12+
// HTTP Basic auth
13+
header('HTTP/1.1 401 Unauthorized');
14+
die('<html><head><meta http-equiv="refresh" content="0; url=/index.php" /></head></html>');
1115
} else {
1216
// HTTP Digest auth
1317
$needed_parts = array(

overview.php

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,24 @@
1010
$server['db'] = 0;
1111
}
1212

13-
// Setup a connection to Redis.
14-
if(isset($server['scheme']) && $server['scheme'] === 'unix' && $server['path']) {
15-
$redis = new Predis\Client(array('scheme' => 'unix', 'path' => $server['path']));
13+
14+
if (isset($config['login_as_acl_auth'])) {
15+
// Currently only support one server at a time
16+
if ($i > 0) {
17+
break;
18+
}
1619
} else {
17-
$redis = !$server['port'] ? new Predis\Client($server['host']) : new Predis\Client('tcp://'.$server['host'].':'.$server['port']);
18-
}
19-
try {
20-
$redis->connect();
21-
} catch (Predis\CommunicationException $exception) {
22-
$redis = false;
20+
// Setup a connection to Redis.
21+
if(isset($server['scheme']) && $server['scheme'] === 'unix' && $server['path']) {
22+
$redis = new Predis\Client(array('scheme' => 'unix', 'path' => $server['path']));
23+
} else {
24+
$redis = !$server['port'] ? new Predis\Client($server['host']) : new Predis\Client('tcp://'.$server['host'].':'.$server['port']);
25+
}
26+
try {
27+
$redis->connect();
28+
} catch (Predis\CommunicationException $exception) {
29+
$redis = false;
30+
}
2331
}
2432

2533
if(!$redis) {
@@ -38,6 +46,9 @@
3846

3947
$info[$i] = $redis->info();
4048
$info[$i]['size'] = $redis->dbSize();
49+
if (isset($config['login_as_acl_auth'])) {
50+
$info[$i]['username'] = $redis->acl->whoami();
51+
}
4152

4253
if (!isset($info[$i]['Server'])) {
4354
$info[$i]['Server'] = array(
@@ -83,6 +94,10 @@
8394

8495
<tr><td><div>Uptime:</div></td><td><div><?php echo format_time($info[$i]['Server']['uptime_in_seconds'])?></div></td></tr>
8596

97+
<?php if(isset($info[$i]['username'])): ?>
98+
<tr><td><div>Username:</div></td><td><div><?php echo ($info[$i]['username'])?></div></td></tr>
99+
<?php endif ?>
100+
86101
<tr><td><div>Last save:</div></td><td><div>
87102
<?php
88103
if (isset($info[$i]['Persistence']['rdb_last_save_time'])) {

0 commit comments

Comments
 (0)