feat(server): allow AUTH and SETNAME options in the HELLO command (#1156)

Signed-off-by: Rueian <rueiancsie@gmail.com>
This commit is contained in:
Rueian 2023-04-28 23:19:40 +08:00 committed by GitHub
parent 494ca14e4e
commit 688f8f51a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 8 deletions

View file

@ -235,11 +235,17 @@ TEST_F(DflyEngineTest, Hello) {
ArgType(RespExpr::STRING), "proto", IntArg(3), "id",
ArgType(RespExpr::INT64), "mode", "standalone", "role", "master"));
// These are valid arguments to HELLO, however as they are not yet supported the implementation
// is degraded to 'unknown command'.
EXPECT_THAT(
Run({"hello", "2", "AUTH", "uname", "pwd"}),
ErrArg("ERR unknown command 'HELLO' with args beginning with: `2`, `AUTH`, `uname`, `pwd`"));
EXPECT_THAT(Run({"hello", "2", "AUTH", "uname", "pwd"}),
ErrArg("WRONGPASS invalid username-password pair or user is disabled."));
EXPECT_THAT(Run({"hello", "2", "AUTH", "default", "pwd"}),
ErrArg("WRONGPASS invalid username-password pair or user is disabled."));
resp = Run({"hello", "3", "AUTH", "default", ""});
ASSERT_THAT(resp, ArrLen(14));
resp = Run({"hello", "3", "AUTH", "default", "", "SETNAME", "myname"});
ASSERT_THAT(resp, ArrLen(14));
}
TEST_F(DflyEngineTest, Memcache) {

View file

@ -625,7 +625,7 @@ bool Service::VerifyCommand(const CommandId* cid, CmdArgList args,
string_view cmd_name{cid->name()};
if (cntx->req_auth && !cntx->authenticated) {
if (cmd_name != "AUTH" && cmd_name != "QUIT") {
if (cmd_name != "AUTH" && cmd_name != "QUIT" && cmd_name != "HELLO") {
(*cntx)->SendError("-NOAUTH Authentication required.");
return false;
}

View file

@ -1757,16 +1757,61 @@ void ServerFamily::Info(CmdArgList args, ConnectionContext* cntx) {
void ServerFamily::Hello(CmdArgList args, ConnectionContext* cntx) {
// If no arguments are provided default to RESP2.
// AUTH and SETNAME options are not supported.
bool is_resp3 = false;
bool has_auth = false;
bool has_setname = false;
string_view username;
string_view password;
string_view clientname;
if (args.size() > 0) {
string_view proto_version = ArgS(args, 0);
is_resp3 = proto_version == "3";
bool valid_proto_version = proto_version == "2" || is_resp3;
if (!valid_proto_version || args.size() > 1) {
if (!valid_proto_version) {
(*cntx)->SendError(UnknownCmd("HELLO", args));
return;
}
for (uint32_t i = 1; i < args.size(); i++) {
auto sub_cmd = ArgS(args, i);
auto moreargs = args.size() - 1 - i;
if (absl::EqualsIgnoreCase(sub_cmd, "AUTH") && moreargs >= 2) {
has_auth = true;
username = ArgS(args, i + 1);
password = ArgS(args, i + 2);
i += 2;
} else if (absl::EqualsIgnoreCase(sub_cmd, "SETNAME") && moreargs > 0) {
has_setname = true;
clientname = ArgS(args, i + 1);
i += 1;
} else {
(*cntx)->SendError(kSyntaxErr);
return;
}
}
}
if (has_auth) {
if (username == "default" && password == GetPassword()) {
cntx->authenticated = true;
} else {
(*cntx)->SendError(facade::kAuthRejected);
return;
}
}
if (cntx->req_auth && !cntx->authenticated) {
(*cntx)->SendError(
"-NOAUTH HELLO must be called with the client already "
"authenticated, otherwise the HELLO <proto> AUTH <user> <pass> "
"option can be used to authenticate the client and "
"select the RESP protocol version at the same time");
return;
}
if (has_setname) {
cntx->owner()->SetName(string{clientname});
}
int proto_version = 2;