Skip to content

Commit

Permalink
Add admin password check
Browse files Browse the repository at this point in the history
  • Loading branch information
kuznetsss committed Sep 12, 2023
1 parent 71e1637 commit 610e692
Show file tree
Hide file tree
Showing 21 changed files with 461 additions and 116 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ target_sources (clio PRIVATE
## Feed
src/feed/SubscriptionManager.cpp
## Web
src/web/impl/AdminVerificationStrategy.cpp
src/web/IntervalSweepHandler.cpp
## RPC
src/rpc/Errors.cpp
Expand Down Expand Up @@ -168,7 +169,6 @@ if (tests)
unittests/rpc/BaseTests.cpp
unittests/rpc/RPCHelpersTests.cpp
unittests/rpc/CountersTests.cpp
unittests/rpc/AdminVerificationTests.cpp
unittests/rpc/APIVersionTests.cpp
unittests/rpc/ForwardingProxyTests.cpp
unittests/rpc/WorkQueueTests.cpp
Expand Down Expand Up @@ -214,6 +214,7 @@ if (tests)
unittests/data/cassandra/ExecutionStrategyTests.cpp
unittests/data/cassandra/AsyncExecutorTests.cpp
# Webserver
unittests/web/AdminVerificationTests.cpp
unittests/web/ServerTests.cpp
unittests/web/RPCServerHandlerTests.cpp
unittests/web/WhitelistHandlerTests.cpp
Expand Down
3 changes: 2 additions & 1 deletion example-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@
"port": 51233,
// Max number of requests to queue up before rejecting further requests.
// Defaults to 0, which disables the limit.
"max_queue_size": 500
"max_queue_size": 500,
"admin_password": "xrp"
},
// Overrides log level on a per logging channel.
// Defaults to global "log_level" for each unspecified channel.
Expand Down
8 changes: 5 additions & 3 deletions src/rpc/Factories.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ make_WsContext(
return Error{{ClioError::rpcINVALID_API_VERSION, apiVersion.error()}};

string command = commandValue.as_string().c_str();
return web::Context(yc, command, *apiVersion, request, session, tagFactory, range, clientIp);
return web::Context(yc, command, *apiVersion, request, session, tagFactory, range, clientIp, session->isAdmin());
}

Expected<web::Context, Status>
Expand All @@ -61,7 +61,8 @@ make_HttpContext(
TagDecoratorFactory const& tagFactory,
data::LedgerRange const& range,
string const& clientIp,
std::reference_wrapper<APIVersionParser const> apiVersionParser)
std::reference_wrapper<APIVersionParser const> apiVersionParser,
bool const isAdmin)
{
using Error = Unexpected<Status>;

Expand Down Expand Up @@ -91,7 +92,8 @@ make_HttpContext(
if (!apiVersion)
return Error{{ClioError::rpcINVALID_API_VERSION, apiVersion.error()}};

return web::Context(yc, command, *apiVersion, array.at(0).as_object(), nullptr, tagFactory, range, clientIp);
return web::Context(
yc, command, *apiVersion, array.at(0).as_object(), nullptr, tagFactory, range, clientIp, isAdmin);
}

} // namespace rpc
4 changes: 3 additions & 1 deletion src/rpc/Factories.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ make_WsContext(
* @param range The ledger range that is available at request time
* @param clientIp The IP address of the connected client
* @param apiVersionParser A parser that is used to parse out the "api_version" field
* @param isAdmin Whether the connection has admin privileges
*/
util::Expected<web::Context, Status>
make_HttpContext(
Expand All @@ -79,6 +80,7 @@ make_HttpContext(
util::TagDecoratorFactory const& tagFactory,
data::LedgerRange const& range,
std::string const& clientIp,
std::reference_wrapper<APIVersionParser const> apiVersionParser);
std::reference_wrapper<APIVersionParser const> apiVersionParser,
bool isAdmin);

} // namespace rpc
16 changes: 5 additions & 11 deletions src/rpc/RPCEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include <rpc/RPCHelpers.h>
#include <rpc/common/AnyHandler.h>
#include <rpc/common/Types.h>
#include <rpc/common/impl/AdminVerificationStrategy.h>
#include <rpc/common/impl/ForwardingProxy.h>
#include <util/Taggable.h>
#include <util/config/Config.h>
Expand Down Expand Up @@ -60,8 +59,7 @@ namespace rpc {
/**
* @brief The RPC engine that ties all RPC-related functionality together.
*/
template <typename AdminVerificationStrategyType>
class RPCEngineBase
class RPCEngine
{
util::Logger perfLog_{"Performance"};
util::Logger log_{"RPC"};
Expand All @@ -76,10 +74,9 @@ class RPCEngineBase
std::shared_ptr<HandlerProvider const> handlerProvider_;

detail::ForwardingProxy<etl::LoadBalancer, Counters, HandlerProvider> forwardingProxy_;
AdminVerificationStrategyType adminVerifier_;

public:
RPCEngineBase(
RPCEngine(
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<feed::SubscriptionManager> const& subscriptions,
std::shared_ptr<etl::LoadBalancer> const& balancer,
Expand All @@ -99,7 +96,7 @@ class RPCEngineBase
{
}

static std::shared_ptr<RPCEngineBase>
static std::shared_ptr<RPCEngine>
make_RPCEngine(
util::Config const& config,
std::shared_ptr<BackendInterface> const& backend,
Expand All @@ -111,7 +108,7 @@ class RPCEngineBase
Counters& counters,
std::shared_ptr<HandlerProvider const> const& handlerProvider)
{
return std::make_shared<RPCEngineBase>(
return std::make_shared<RPCEngine>(
backend, subscriptions, balancer, etl, dosGuard, workQueue, counters, handlerProvider);
}

Expand Down Expand Up @@ -145,8 +142,7 @@ class RPCEngineBase
{
LOG(perfLog_.debug()) << ctx.tag() << " start executing rpc `" << ctx.method << '`';

auto const isAdmin = adminVerifier_.isAdmin(ctx.clientIp);
auto const context = Context{ctx.yield, ctx.session, isAdmin, ctx.clientIp, ctx.apiVersion};
auto const context = Context{ctx.yield, ctx.session, ctx.isAdmin, ctx.clientIp, ctx.apiVersion};
auto const v = (*method).process(ctx.params, context);

LOG(perfLog_.debug()) << ctx.tag() << " finish executing rpc `" << ctx.method << '`';
Expand Down Expand Up @@ -286,6 +282,4 @@ class RPCEngineBase
}
};

using RPCEngine = RPCEngineBase<detail::IPAdminVerificationStrategy>;

} // namespace rpc
6 changes: 5 additions & 1 deletion src/web/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct Context : util::Taggable
std::shared_ptr<web::ConnectionBase> session;
data::LedgerRange range;
std::string clientIp;
bool isAdmin;

/**
* @brief Create a new Context instance.
Expand All @@ -56,6 +57,7 @@ struct Context : util::Taggable
* @param tagFactory A factory that is used to generate tags to track requests and connections
* @param range The ledger range that is available at the time of the request
* @param clientIp IP of the peer
* @param isAdmin Whether the peer has admin privileges
*/
Context(
boost::asio::yield_context yield,
Expand All @@ -65,7 +67,8 @@ struct Context : util::Taggable
std::shared_ptr<web::ConnectionBase> const& session,
util::TagDecoratorFactory const& tagFactory,
data::LedgerRange const& range,
std::string const& clientIp)
std::string const& clientIp,
bool isAdmin)
: Taggable(tagFactory)
, yield(yield)
, method(command)
Expand All @@ -74,6 +77,7 @@ struct Context : util::Taggable
, session(session)
, range(range)
, clientIp(clientIp)
, isAdmin(isAdmin)
{
static util::Logger perfLog{"Performance"};
LOG(perfLog.debug()) << tag() << "new Context created";
Expand Down
13 changes: 11 additions & 2 deletions src/web/HttpSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class HttpSession : public detail::HttpBase<HttpSession, HandlerType>,
*
* @param socket The socket. Ownership is transferred to HttpSession
* @param ip Client's IP address
* @param adminPassword The optional password to verify admin role in requests
* @param tagFactory A factory that is used to generate tags to track requests and sessions
* @param dosGuard The denial of service guard to use
* @param handler The server handler to use
Expand All @@ -55,11 +56,18 @@ class HttpSession : public detail::HttpBase<HttpSession, HandlerType>,
explicit HttpSession(
tcp::socket&& socket,
std::string const& ip,
std::optional<std::string> adminPassword,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<web::DOSGuard> dosGuard,
std::shared_ptr<HandlerType> const& handler,
boost::beast::flat_buffer buffer)
: detail::HttpBase<HttpSession, HandlerType>(ip, tagFactory, dosGuard, handler, std::move(buffer))
: detail::HttpBase<HttpSession, HandlerType>(
ip,
tagFactory,
std::move(adminPassword),
dosGuard,
handler,
std::move(buffer))
, stream_(std::move(socket))
, tagFactory_(tagFactory)
{
Expand Down Expand Up @@ -103,7 +111,8 @@ class HttpSession : public detail::HttpBase<HttpSession, HandlerType>,
this->dosGuard_,
this->handler_,
std::move(this->buffer_),
std::move(this->req_))
std::move(this->req_),
ConnectionBase::isAdmin())
->run();
}
};
Expand Down
15 changes: 10 additions & 5 deletions src/web/PlainWsSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,20 @@ class PlainWsSession : public detail::WsBase<PlainWsSession, HandlerType>
* @param dosGuard The denial of service guard to use
* @param handler The server handler to use
* @param buffer Buffer with initial data received from the peer
* @param isAdmin Whether the connection has admin privileges
*/
explicit PlainWsSession(
boost::asio::ip::tcp::socket&& socket,
std::string ip,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<web::DOSGuard> dosGuard,
std::shared_ptr<HandlerType> const& handler,
boost::beast::flat_buffer&& buffer)
boost::beast::flat_buffer&& buffer,
bool isAdmin)
: detail::WsBase<PlainWsSession, HandlerType>(ip, tagFactory, dosGuard, handler, std::move(buffer))
, ws_(std::move(socket))
{
ConnectionBase::isAdmin_ = isAdmin;
}

~PlainWsSession() = default;
Expand Down Expand Up @@ -85,6 +88,7 @@ class WsUpgrader : public std::enable_shared_from_this<WsUpgrader<HandlerType>>
http::request<http::string_body> req_;
std::string ip_;
std::shared_ptr<HandlerType> const handler_;
bool isAdmin_;

public:
/**
Expand All @@ -97,6 +101,7 @@ class WsUpgrader : public std::enable_shared_from_this<WsUpgrader<HandlerType>>
* @param handler The server handler to use
* @param buffer Buffer with initial data received from the peer. Ownership is transferred
* @param request The request. Ownership is transferred
* @param isAdmin Whether the connection has admin privileges
*/
WsUpgrader(
boost::beast::tcp_stream&& stream,
Expand All @@ -105,19 +110,19 @@ class WsUpgrader : public std::enable_shared_from_this<WsUpgrader<HandlerType>>
std::reference_wrapper<web::DOSGuard> dosGuard,
std::shared_ptr<HandlerType> const& handler,
boost::beast::flat_buffer&& buffer,
http::request<http::string_body> request)
http::request<http::string_body> request,
bool isAdmin)
: http_(std::move(stream))
, buffer_(std::move(buffer))
, tagFactory_(tagFactory)
, dosGuard_(dosGuard)
, req_(std::move(request))
, ip_(ip)
, handler_(handler)
, isAdmin_(isAdmin)
{
}

WsUpgrader() = default;

/** @brief Initiate the upgrade. */
void
run()
Expand Down Expand Up @@ -150,7 +155,7 @@ class WsUpgrader : public std::enable_shared_from_this<WsUpgrader<HandlerType>>
boost::beast::get_lowest_layer(http_).expires_never();

std::make_shared<PlainWsSession<HandlerType>>(
http_.release_socket(), ip_, tagFactory_, dosGuard_, handler_, std::move(buffer_))
http_.release_socket(), ip_, tagFactory_, dosGuard_, handler_, std::move(buffer_), isAdmin_)
->run(std::move(req_));
}
};
Expand Down
3 changes: 2 additions & 1 deletion src/web/RPCServerHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ class RPCServerHandler
tagFactory_.with(connection->tag()),
*range,
connection->clientIp,
std::cref(apiVersionParser_));
std::cref(apiVersionParser_),
connection->isAdmin());
}();

if (!context)
Expand Down
Loading

0 comments on commit 610e692

Please sign in to comment.