Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
beebb3c0
Commit
beebb3c0
authored
Oct 01, 2019
by
antirez
Browse files
Merge branch 'hashed-pass-opcode' into unstable
parents
a9628142
09041b93
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/acl.c
View file @
beebb3c0
...
@@ -94,6 +94,9 @@ void ACLResetSubcommandsForCommand(user *u, unsigned long id);
...
@@ -94,6 +94,9 @@ void ACLResetSubcommandsForCommand(user *u, unsigned long id);
void
ACLResetSubcommands
(
user
*
u
);
void
ACLResetSubcommands
(
user
*
u
);
void
ACLAddAllowedSubcommand
(
user
*
u
,
unsigned
long
id
,
const
char
*
sub
);
void
ACLAddAllowedSubcommand
(
user
*
u
,
unsigned
long
id
,
const
char
*
sub
);
/* The length of the string representation of a hashed password. */
#define HASH_PASSWORD_LEN SHA256_BLOCK_SIZE*2
/* =============================================================================
/* =============================================================================
* Helper functions for the rest of the ACL implementation
* Helper functions for the rest of the ACL implementation
* ==========================================================================*/
* ==========================================================================*/
...
@@ -145,7 +148,7 @@ int time_independent_strcmp(char *a, char *b) {
...
@@ -145,7 +148,7 @@ int time_independent_strcmp(char *a, char *b) {
sds
ACLHashPassword
(
unsigned
char
*
cleartext
,
size_t
len
)
{
sds
ACLHashPassword
(
unsigned
char
*
cleartext
,
size_t
len
)
{
SHA256_CTX
ctx
;
SHA256_CTX
ctx
;
unsigned
char
hash
[
SHA256_BLOCK_SIZE
];
unsigned
char
hash
[
SHA256_BLOCK_SIZE
];
char
hex
[
S
HA
256_BLOCK_SIZE
*
2
];
char
hex
[
HA
SH_PASSWORD_LEN
];
char
*
cset
=
"0123456789abcdef"
;
char
*
cset
=
"0123456789abcdef"
;
sha256_init
(
&
ctx
);
sha256_init
(
&
ctx
);
...
@@ -156,7 +159,7 @@ sds ACLHashPassword(unsigned char *cleartext, size_t len) {
...
@@ -156,7 +159,7 @@ sds ACLHashPassword(unsigned char *cleartext, size_t len) {
hex
[
j
*
2
]
=
cset
[((
hash
[
j
]
&
0xF0
)
>>
4
)];
hex
[
j
*
2
]
=
cset
[((
hash
[
j
]
&
0xF0
)
>>
4
)];
hex
[
j
*
2
+
1
]
=
cset
[(
hash
[
j
]
&
0xF
)];
hex
[
j
*
2
+
1
]
=
cset
[(
hash
[
j
]
&
0xF
)];
}
}
return
sdsnewlen
(
hex
,
S
HA
256_BLOCK_SIZE
*
2
);
return
sdsnewlen
(
hex
,
HA
SH_PASSWORD_LEN
);
}
}
/* =============================================================================
/* =============================================================================
...
@@ -522,7 +525,7 @@ sds ACLDescribeUser(user *u) {
...
@@ -522,7 +525,7 @@ sds ACLDescribeUser(user *u) {
listRewind
(
u
->
passwords
,
&
li
);
listRewind
(
u
->
passwords
,
&
li
);
while
((
ln
=
listNext
(
&
li
)))
{
while
((
ln
=
listNext
(
&
li
)))
{
sds
thispass
=
listNodeValue
(
ln
);
sds
thispass
=
listNodeValue
(
ln
);
res
=
sdscatlen
(
res
,
"
>
"
,
1
);
res
=
sdscatlen
(
res
,
"
#
"
,
1
);
res
=
sdscatsds
(
res
,
thispass
);
res
=
sdscatsds
(
res
,
thispass
);
res
=
sdscatlen
(
res
,
" "
,
1
);
res
=
sdscatlen
(
res
,
" "
,
1
);
}
}
...
@@ -649,7 +652,14 @@ void ACLAddAllowedSubcommand(user *u, unsigned long id, const char *sub) {
...
@@ -649,7 +652,14 @@ void ACLAddAllowedSubcommand(user *u, unsigned long id, const char *sub) {
* ><password> Add this password to the list of valid password for the user.
* ><password> Add this password to the list of valid password for the user.
* For example >mypass will add "mypass" to the list.
* For example >mypass will add "mypass" to the list.
* This directive clears the "nopass" flag (see later).
* This directive clears the "nopass" flag (see later).
* #<hash> Add this password hash to the list of valid hashes for
* the user. This is useful if you have previously computed
* the hash, and don't want to store it in plaintext.
* This directive clears the "nopass" flag (see later).
* <<password> Remove this password from the list of valid passwords.
* <<password> Remove this password from the list of valid passwords.
* !<hash> Remove this hashed password from the list of valid passwords.
* This is useful when you want to remove a password just by
* hash without knowing its plaintext version at all.
* nopass All the set passwords of the user are removed, and the user
* nopass All the set passwords of the user are removed, and the user
* is flagged as requiring no password: it means that every
* is flagged as requiring no password: it means that every
* password will work against this user. If this directive is
* password will work against this user. If this directive is
...
@@ -685,6 +695,7 @@ void ACLAddAllowedSubcommand(user *u, unsigned long id, const char *sub) {
...
@@ -685,6 +695,7 @@ void ACLAddAllowedSubcommand(user *u, unsigned long id, const char *sub) {
* EEXIST: You are adding a key pattern after "*" was already added. This is
* EEXIST: You are adding a key pattern after "*" was already added. This is
* almost surely an error on the user side.
* almost surely an error on the user side.
* ENODEV: The password you are trying to remove from the user does not exist.
* ENODEV: The password you are trying to remove from the user does not exist.
* EBADMSG: The hash you are trying to add is not a valid hash.
*/
*/
int
ACLSetUser
(
user
*
u
,
const
char
*
op
,
ssize_t
oplen
)
{
int
ACLSetUser
(
user
*
u
,
const
char
*
op
,
ssize_t
oplen
)
{
if
(
oplen
==
-
1
)
oplen
=
strlen
(
op
);
if
(
oplen
==
-
1
)
oplen
=
strlen
(
op
);
...
@@ -720,8 +731,30 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen) {
...
@@ -720,8 +731,30 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen) {
}
else
if
(
!
strcasecmp
(
op
,
"resetpass"
))
{
}
else
if
(
!
strcasecmp
(
op
,
"resetpass"
))
{
u
->
flags
&=
~
USER_FLAG_NOPASS
;
u
->
flags
&=
~
USER_FLAG_NOPASS
;
listEmpty
(
u
->
passwords
);
listEmpty
(
u
->
passwords
);
}
else
if
(
op
[
0
]
==
'>'
)
{
}
else
if
(
op
[
0
]
==
'>'
||
op
[
0
]
==
'#'
)
{
sds
newpass
=
ACLHashPassword
((
unsigned
char
*
)
op
+
1
,
oplen
-
1
);
sds
newpass
;
if
(
op
[
0
]
==
'>'
)
{
newpass
=
ACLHashPassword
((
unsigned
char
*
)
op
+
1
,
oplen
-
1
);
}
else
{
if
(
oplen
!=
HASH_PASSWORD_LEN
+
1
)
{
errno
=
EBADMSG
;
return
C_ERR
;
}
/* Password hashes can only be characters that represent
* hexadecimal values, which are numbers and lowercase
* characters 'a' through 'f'.
*/
for
(
int
i
=
1
;
i
<
HASH_PASSWORD_LEN
+
1
;
i
++
)
{
char
c
=
op
[
i
];
if
((
c
<
'a'
||
c
>
'f'
)
&&
(
c
<
'0'
||
c
>
'9'
))
{
errno
=
EBADMSG
;
return
C_ERR
;
}
}
newpass
=
sdsnewlen
(
op
+
1
,
oplen
-
1
);
}
listNode
*
ln
=
listSearchKey
(
u
->
passwords
,
newpass
);
listNode
*
ln
=
listSearchKey
(
u
->
passwords
,
newpass
);
/* Avoid re-adding the same password multiple times. */
/* Avoid re-adding the same password multiple times. */
if
(
ln
==
NULL
)
if
(
ln
==
NULL
)
...
@@ -729,8 +762,17 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen) {
...
@@ -729,8 +762,17 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen) {
else
else
sdsfree
(
newpass
);
sdsfree
(
newpass
);
u
->
flags
&=
~
USER_FLAG_NOPASS
;
u
->
flags
&=
~
USER_FLAG_NOPASS
;
}
else
if
(
op
[
0
]
==
'<'
)
{
}
else
if
(
op
[
0
]
==
'<'
||
op
[
0
]
==
'!'
)
{
sds
delpass
=
ACLHashPassword
((
unsigned
char
*
)
op
+
1
,
oplen
-
1
);
sds
delpass
;
if
(
op
[
0
]
==
'<'
)
{
delpass
=
ACLHashPassword
((
unsigned
char
*
)
op
+
1
,
oplen
-
1
);
}
else
{
if
(
oplen
!=
HASH_PASSWORD_LEN
+
1
)
{
errno
=
EBADMSG
;
return
C_ERR
;
}
delpass
=
sdsnewlen
(
op
+
1
,
oplen
-
1
);
}
listNode
*
ln
=
listSearchKey
(
u
->
passwords
,
delpass
);
listNode
*
ln
=
listSearchKey
(
u
->
passwords
,
delpass
);
sdsfree
(
delpass
);
sdsfree
(
delpass
);
if
(
ln
)
{
if
(
ln
)
{
...
@@ -848,6 +890,9 @@ char *ACLSetUserStringError(void) {
...
@@ -848,6 +890,9 @@ char *ACLSetUserStringError(void) {
else
if
(
errno
==
ENODEV
)
else
if
(
errno
==
ENODEV
)
errmsg
=
"The password you are trying to remove from the user does "
errmsg
=
"The password you are trying to remove from the user does "
"not exist"
;
"not exist"
;
else
if
(
errno
==
EBADMSG
)
errmsg
=
"The password hash must be exactly 64 characters and contain "
"only lowercase hexadecimal characters"
;
return
errmsg
;
return
errmsg
;
}
}
...
...
tests/support/test.tcl
View file @
beebb3c0
...
@@ -15,6 +15,12 @@ proc assert {condition} {
...
@@ -15,6 +15,12 @@ proc assert {condition} {
}
}
}
}
proc assert_no_match
{
pattern value
}
{
if
{[
string match $pattern $value
]}
{
error
"assertion:Expected '
$value
' to not match '
$pattern
'"
}
}
proc assert_match
{
pattern value
}
{
proc assert_match
{
pattern value
}
{
if
{
!
[
string match $pattern $value
]}
{
if
{
!
[
string match $pattern $value
]}
{
error
"assertion:Expected '
$value
' to match '
$pattern
'"
error
"assertion:Expected '
$value
' to match '
$pattern
'"
...
...
tests/unit/acl.tcl
View file @
beebb3c0
...
@@ -35,6 +35,32 @@ start_server {tags {"acl"}} {
...
@@ -35,6 +35,32 @@ start_server {tags {"acl"}} {
set e
set e
}
{
*WRONGPASS*
}
}
{
*WRONGPASS*
}
test
{
Test password hashes can be added
}
{
r ACL setuser newuser #34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4e6
catch
{
r AUTH newuser passwd4
}
e
assert
{
$e
eq
"OK"
}
}
test
{
Test password hashes validate input
}
{
# Validate Length
catch
{
r ACL setuser newuser #34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4e
}
e
# Validate character outside set
catch
{
r ACL setuser newuser #34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4eq
}
e
set e
}
{
*Error in ACL SETUSER modifier*
}
test
{
ACL GETUSER returns the password hash instead of the actual password
}
{
set passstr
[
dict get
[
r ACL getuser newuser
]
passwords
]
assert_match
{
*34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4e6*
}
$passstr
assert_no_match
{
*passwd4*
}
$passstr
}
test
{
Test hashed passwords removal
}
{
r ACL setuser newuser !34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4e6
set passstr
[
dict get
[
r ACL getuser newuser
]
passwords
]
assert_no_match
{
*34344e4d60c2b6d639b7bd22e18f2b0b91bc34bf0ac5f9952744435093cfb4e6*
}
$passstr
}
test
{
By default users are not able to access any command
}
{
test
{
By default users are not able to access any command
}
{
catch
{
r SET foo bar
}
e
catch
{
r SET foo bar
}
e
set e
set e
...
@@ -67,7 +93,7 @@ start_server {tags {"acl"}} {
...
@@ -67,7 +93,7 @@ start_server {tags {"acl"}} {
set e
set e
}
{
*NOPERM*
}
}
{
*NOPERM*
}
test
{
ACLs can include or exclu
s
e whole classes of commands
}
{
test
{
ACLs can include or exclu
d
e whole classes of commands
}
{
r ACL setuser newuser -@all +@set +acl
r ACL setuser newuser -@all +@set +acl
r SADD myset a b c
;
# Should not raise an error
r SADD myset a b c
;
# Should not raise an error
r ACL setuser newuser +@all -@string
r ACL setuser newuser +@all -@string
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment