Commit 2216c025 authored by Georgios Bitzes's avatar Georgios Bitzes
Browse files

Implement and test a dispatcher to perform authentication

parent 14ea5e52
Pipeline #407484 passed with stages
in 32 minutes and 33 seconds
......@@ -12,78 +12,80 @@ include_directories(
add_definitions(${GCOV_CFLAGS})
add_library(XrdQuarkDB SHARED
XrdPlugin.cc
XrdQuarkDB.cc XrdQuarkDB.hh
Configuration.cc Configuration.hh
Utils.cc Utils.hh
Common.hh
Link.cc Link.hh
BufferedReader.cc BufferedReader.hh
BufferedWriter.cc BufferedWriter.hh
RedisParser.cc RedisParser.hh
RedisRequest.cc RedisRequest.hh
StateMachine.cc StateMachine.hh
Commands.cc Commands.hh
Formatter.cc Formatter.hh
Dispatcher.cc Dispatcher.hh
Poller.cc Poller.hh
Connection.cc Connection.hh
QuarkDBNode.cc QuarkDBNode.hh
Shard.cc Shard.hh
ShardDirectory.cc ShardDirectory.hh
XrdQuarkDB.cc XrdQuarkDB.hh
Configuration.cc Configuration.hh
Utils.cc Utils.hh
Common.hh
Link.cc Link.hh
BufferedReader.cc BufferedReader.hh
BufferedWriter.cc BufferedWriter.hh
RedisParser.cc RedisParser.hh
RedisRequest.cc RedisRequest.hh
StateMachine.cc StateMachine.hh
Commands.cc Commands.hh
Formatter.cc Formatter.hh
Dispatcher.cc Dispatcher.hh
Poller.cc Poller.hh
Connection.cc Connection.hh
QuarkDBNode.cc QuarkDBNode.hh
Shard.cc Shard.hh
ShardDirectory.cc ShardDirectory.hh
raft/RaftBlockedWrites.cc raft/RaftBlockedWrites.hh
raft/RaftConfig.cc raft/RaftConfig.hh
raft/RaftJournal.cc raft/RaftJournal.hh
raft/RaftState.cc raft/RaftState.hh
raft/RaftTalker.cc raft/RaftTalker.hh
raft/RaftUtils.cc raft/RaftUtils.hh
raft/RaftDispatcher.cc raft/RaftDispatcher.hh
raft/RaftReplicator.cc raft/RaftReplicator.hh
raft/RaftResilverer.cc raft/RaftResilverer.hh
raft/RaftTimeouts.cc raft/RaftTimeouts.hh
raft/RaftDirector.cc raft/RaftDirector.hh
raft/RaftCommitTracker.cc raft/RaftCommitTracker.hh
raft/RaftWriteTracker.cc raft/RaftWriteTracker.hh
raft/RaftGroup.cc raft/RaftGroup.hh
raft/RaftMembers.hh
raft/RaftTrimmer.cc raft/RaftTrimmer.hh
raft/RaftLease.cc raft/RaftLease.hh
auth/AuthenticationDispatcher.cc auth/AuthenticationDispatcher.hh
recovery/RecoveryDispatcher.cc recovery/RecoveryDispatcher.hh
recovery/RecoveryEditor.cc recovery/RecoveryEditor.hh
recovery/RecoveryRunner.cc recovery/RecoveryRunner.hh
raft/RaftBlockedWrites.cc raft/RaftBlockedWrites.hh
raft/RaftConfig.cc raft/RaftConfig.hh
raft/RaftJournal.cc raft/RaftJournal.hh
raft/RaftState.cc raft/RaftState.hh
raft/RaftTalker.cc raft/RaftTalker.hh
raft/RaftUtils.cc raft/RaftUtils.hh
raft/RaftDispatcher.cc raft/RaftDispatcher.hh
raft/RaftReplicator.cc raft/RaftReplicator.hh
raft/RaftResilverer.cc raft/RaftResilverer.hh
raft/RaftTimeouts.cc raft/RaftTimeouts.hh
raft/RaftDirector.cc raft/RaftDirector.hh
raft/RaftCommitTracker.cc raft/RaftCommitTracker.hh
raft/RaftWriteTracker.cc raft/RaftWriteTracker.hh
raft/RaftGroup.cc raft/RaftGroup.hh
raft/RaftMembers.hh
raft/RaftTrimmer.cc raft/RaftTrimmer.hh
raft/RaftLease.cc raft/RaftLease.hh
redis/ArrayResponseBuilder.cc redis/ArrayResponseBuilder.hh
redis/Authenticator.cc redis/Authenticator.hh
redis/CommandMonitor.cc redis/CommandMonitor.hh
redis/MultiHandler.cc redis/MultiHandler.hh
redis/MultiOp.cc redis/MultiOp.hh
redis/RedisEncodedResponse.hh
recovery/RecoveryDispatcher.cc recovery/RecoveryDispatcher.hh
recovery/RecoveryEditor.cc recovery/RecoveryEditor.hh
recovery/RecoveryRunner.cc recovery/RecoveryRunner.hh
storage/ConsistencyScanner.cc storage/ConsistencyScanner.hh
storage/KeyConstants.cc storage/KeyConstants.hh
storage/KeyDescriptor.hh
storage/KeyDescriptorBuilder.cc storage/KeyDescriptorBuilder.hh
storage/KeyLocators.hh
storage/PatternMatching.hh
storage/ReverseLocator.hh
storage/StagingArea.hh
redis/ArrayResponseBuilder.cc redis/ArrayResponseBuilder.hh
redis/Authenticator.cc redis/Authenticator.hh
redis/CommandMonitor.cc redis/CommandMonitor.hh
redis/MultiHandler.cc redis/MultiHandler.hh
redis/MultiOp.cc redis/MultiOp.hh
redis/RedisEncodedResponse.hh
utils/AssistedThread.hh
utils/CommandParsing.hh
utils/DirectoryIterator.cc utils/DirectoryIterator.hh
utils/FileUtils.cc utils/FileUtils.hh
utils/IntToBinaryString.hh
utils/ParseUtils.hh
utils/Random.cc utils/Random.hh
utils/RequestCounter.cc utils/RequestCounter.hh
utils/Resilvering.cc utils/Resilvering.hh
utils/ScopedAdder.hh
utils/StaticBuffer.hh
utils/StringUtils.cc utils/StringUtils.hh
utils/TimeFormatting.cc utils/TimeFormatting.hh
utils/Uuid.hh
utils/VectorUtils.hh
storage/ConsistencyScanner.cc storage/ConsistencyScanner.hh
storage/KeyConstants.cc storage/KeyConstants.hh
storage/KeyDescriptor.hh
storage/KeyDescriptorBuilder.cc storage/KeyDescriptorBuilder.hh
storage/KeyLocators.hh
storage/PatternMatching.hh
storage/ReverseLocator.hh
storage/StagingArea.hh
utils/AssistedThread.hh
utils/CommandParsing.hh
utils/DirectoryIterator.cc utils/DirectoryIterator.hh
utils/FileUtils.cc utils/FileUtils.hh
utils/IntToBinaryString.hh
utils/ParseUtils.hh
utils/Random.cc utils/Random.hh
utils/RequestCounter.cc utils/RequestCounter.hh
utils/Resilvering.cc utils/Resilvering.hh
utils/ScopedAdder.hh
utils/StaticBuffer.hh
utils/StringUtils.cc utils/StringUtils.hh
utils/TimeFormatting.cc utils/TimeFormatting.hh
utils/Uuid.hh
utils/VectorUtils.hh
${BACKWARD_ENABLE}
)
......
......@@ -35,6 +35,7 @@ struct cmdMapInit {
redis_cmd_map["debug"] = {RedisCommand::DEBUG, CommandType::CONTROL};
redis_cmd_map["monitor"] = {RedisCommand::MONITOR, CommandType::CONTROL};
redis_cmd_map["client_id"] = {RedisCommand::CLIENT_ID, CommandType::CONTROL};
redis_cmd_map["auth"] = {RedisCommand::AUTH, CommandType::AUTHENTICATION};
redis_cmd_map["get"] = {RedisCommand::GET, CommandType::READ};
redis_cmd_map["exists"] = {RedisCommand::EXISTS, CommandType::READ};
......
......@@ -44,6 +44,7 @@ enum class RedisCommand {
DEL,
KEYS,
SCAN,
AUTH,
HGET,
HSET,
......@@ -135,7 +136,8 @@ enum class CommandType {
MULTIOP,
CONTROL,
RAFT,
QUARKDB
QUARKDB,
AUTHENTICATION
};
#define QDB_ALWAYS_INLINE __attribute__((always_inline))
......
......@@ -137,6 +137,8 @@ public:
bool raftStaleReads = false;
bool raftAuthorization = false;
bool authorization = false;
LinkStatus processRequests(Dispatcher *dispatcher, const InFlightTracker &tracker);
void setResponseBuffering(bool value);
void flush();
......
// ----------------------------------------------------------------------
// File: AuthenticationDispatcher.cc
// Author: Georgios Bitzes - CERN
// ----------------------------------------------------------------------
/************************************************************************
* quarkdb - a redis-like highly available key-value store *
* Copyright (C) 2016 CERN/Switzerland *
* *
* 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, either version 3 of the License, or *
* (at your option) any later version. *
* *
* 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. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
************************************************************************/
#include "../utils/Macros.hh"
#include "AuthenticationDispatcher.hh"
#include "../Formatter.hh"
using namespace quarkdb;
AuthenticationDispatcher::AuthenticationDispatcher(const std::string &secr)
: secret(secr) {
if(secret.size() < 32u && !secret.empty()) {
qdb_throw("Password is too small, minimum length is 32");
}
}
RedisEncodedResponse AuthenticationDispatcher::dispatch(const RedisRequest &req, bool &authorized) {
authorized = secret.empty();
switch(req.getCommand()) {
case RedisCommand::AUTH: {
if(req.size() != 2u) return Formatter::errArgs(req[0]);
if(secret.empty()) return Formatter::err("Client sent AUTH, but no password is set");
qdb_warn("A client used AUTH, which is highly discouraged.");
if(secret != req[1]) {
qdb_warn("A password attempt was made with an invalid password");
return Formatter::err("invalid password");
}
authorized = true;
return Formatter::ok();
}
default: {
qdb_throw("Internal dispatching error for command " << req.toPrintableString());
}
}
}
LinkStatus AuthenticationDispatcher::dispatch(Connection *conn, RedisRequest &req) {
return conn->raw(dispatch(req, conn->authorization));
}
//----------------------------------------------------------------------
// File: AuthenticationDispatcher.hh
// Author: Georgios Bitzes - CERN
// ----------------------------------------------------------------------
/************************************************************************
* quarkdb - a redis-like highly available key-value store *
* Copyright (C) 2018 CERN/Switzerland *
* *
* 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, either version 3 of the License, or *
* (at your option) any later version. *
* *
* 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. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
************************************************************************/
#ifndef QUARKDB_AUTHENTICATION_DISPATCHER_H
#define QUARKDB_AUTHENTICATION_DISPATCHER_H
#include "../Dispatcher.hh"
namespace quarkdb {
class QuarkDBNode;
class AuthenticationDispatcher : public Dispatcher {
public:
AuthenticationDispatcher(const std::string &secret);
virtual LinkStatus dispatch(Connection *conn, RedisRequest &req) override final;
RedisEncodedResponse dispatch(const RedisRequest &req, bool &authorized);
private:
std::string secret;
};
}
#endif
......@@ -37,6 +37,10 @@ public:
RedisEncodedResponse() {}
bool empty() const { return val.empty(); }
std::string val;
bool operator==(const RedisEncodedResponse &other) const {
return val == other.val;
}
};
}
......
......@@ -23,6 +23,8 @@
#include "utils/FileUtils.hh"
#include "utils/Macros.hh"
#include "auth/AuthenticationDispatcher.hh"
#include "test-utils.hh"
#include <gtest/gtest.h>
using namespace quarkdb;
......@@ -65,3 +67,33 @@ TEST(ReadPasswordFile, BasicSanity) {
ASSERT_EQ(system("rm -f /tmp/quarkdb-tests/auth/f1"), 0);
}
TEST(AuthenticationDispatcher, NoPassword) {
AuthenticationDispatcher dispatcher("");
bool authorized = false;
ASSERT_EQ(Formatter::errArgs("AUTH"), dispatcher.dispatch(make_req("AUTH"), authorized));
ASSERT_TRUE(authorized);
ASSERT_EQ(Formatter::err("Client sent AUTH, but no password is set").val, dispatcher.dispatch(make_req("AUTH", "test"), authorized).val);
ASSERT_TRUE(authorized);
}
TEST(AuthenticationDispatcher, TooSmallPassword) {
ASSERT_THROW(AuthenticationDispatcher("hunter2"), FatalException);
}
TEST(AuthenticationDispatcher, AuthBasicSanity) {
AuthenticationDispatcher dispatcher("hunter2_hunter2_hunter2_hunter2_hunter2");
bool authorized = false;
ASSERT_EQ(Formatter::errArgs("AUTH"), dispatcher.dispatch(make_req("AUTH"), authorized));
ASSERT_FALSE(authorized);
ASSERT_EQ(Formatter::err("invalid password"), dispatcher.dispatch(make_req("AUTH", "hunter3"), authorized ));
ASSERT_FALSE(authorized);
ASSERT_EQ(Formatter::ok(), dispatcher.dispatch(make_req("AUTH", "hunter2_hunter2_hunter2_hunter2_hunter2"), authorized ));
ASSERT_TRUE(authorized);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment