Permalink
Browse files

Added mandatory authentication to all RPC interfaces and a correspond…

…ing override flag.
  • Loading branch information...
nnamon committed Feb 1, 2018
1 parent df303ba commit 4949e91e09bc1d16132090aef4dc09cc6ca09fa1
@@ -37,11 +37,12 @@
namespace CryptoNote {
JsonRpcServer::JsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, Logging::ILogger& loggerGroup) :
JsonRpcServer::JsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, Logging::ILogger& loggerGroup, PaymentService::Configuration& config) :
HttpServer(sys, loggerGroup),
system(sys),
stopEvent(stopEvent),
logger(loggerGroup, "JsonRpcServer")
logger(loggerGroup, "JsonRpcServer"),
config(config)
{
}
@@ -164,6 +165,23 @@ void JsonRpcServer::makeMethodNotFoundResponse(Common::JsonValue& resp) {
resp.insert("error", error);
}
void JsonRpcServer::makeInvalidPasswordResponse(Common::JsonValue& resp) {
using Common::JsonValue;
JsonValue error(JsonValue::OBJECT);
JsonValue code;
code = static_cast<int64_t>(-32604);
JsonValue message;
message = "Invalid or no rpc password";
error.insert("code", code);
error.insert("message", message);
resp.insert("error", error);
}
void JsonRpcServer::fillJsonResponse(const Common::JsonValue& v, Common::JsonValue& resp) {
resp.insert("result", v);
}
@@ -24,6 +24,7 @@
#include "Logging/ILogger.h"
#include "Logging/LoggerRef.h"
#include "Rpc/HttpServer.h"
#include "PaymentGateService/PaymentServiceConfiguration.h"
namespace CryptoNote {
@@ -43,20 +44,22 @@ namespace CryptoNote {
class JsonRpcServer : HttpServer {
public:
JsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, Logging::ILogger& loggerGroup);
JsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, Logging::ILogger& loggerGroup, PaymentService::Configuration& config);
JsonRpcServer(const JsonRpcServer&) = delete;
void start(const std::string& bindAddress, uint16_t bindPort);
protected:
static void makeErrorResponse(const std::error_code& ec, Common::JsonValue& resp);
static void makeMethodNotFoundResponse(Common::JsonValue& resp);
static void makeInvalidPasswordResponse(Common::JsonValue& resp);
static void makeGenericErrorReponse(Common::JsonValue& resp, const char* what, int errorCode = -32001);
static void fillJsonResponse(const Common::JsonValue& v, Common::JsonValue& resp);
static void prepareJsonResponse(const Common::JsonValue& req, Common::JsonValue& resp);
static void makeJsonParsingErrorResponse(Common::JsonValue& resp);
virtual void processJsonRpcRequest(const Common::JsonValue& req, Common::JsonValue& resp) = 0;
PaymentService::Configuration& config;
private:
// HttpServer
@@ -25,10 +25,12 @@
#include "Serialization/JsonInputValueSerializer.h"
#include "Serialization/JsonOutputStreamSerializer.h"
#include "Rpc/JsonRpc.h"
namespace PaymentService {
PaymentServiceJsonRpcServer::PaymentServiceJsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, WalletService& service, Logging::ILogger& loggerGroup)
: JsonRpcServer(sys, stopEvent, loggerGroup)
PaymentServiceJsonRpcServer::PaymentServiceJsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, WalletService& service, Logging::ILogger& loggerGroup, PaymentService::Configuration& config)
: JsonRpcServer(sys, stopEvent, loggerGroup, config)
, service(service)
, logger(loggerGroup, "PaymentServiceJsonRpcServer")
{
@@ -60,6 +62,23 @@ PaymentServiceJsonRpcServer::PaymentServiceJsonRpcServer(System::Dispatcher& sys
void PaymentServiceJsonRpcServer::processJsonRpcRequest(const Common::JsonValue& req, Common::JsonValue& resp) {
try {
prepareJsonResponse(req, resp);
if (!config.legacySecurity) {
std::string clientPassword;
if (!req.contains("password")) {
makeInvalidPasswordResponse(resp);
return;
}
if (!req("password").isString()) {
makeInvalidPasswordResponse(resp);
return;
}
clientPassword = req("password").getString();
if (clientPassword != config.rpcPassword) {
makeInvalidPasswordResponse(resp);
return;
}
}
if (!req.contains("method")) {
logger(Logging::WARNING) << "Field \"method\" is not found in json request: " << req;
@@ -31,7 +31,7 @@ class WalletService;
class PaymentServiceJsonRpcServer : public CryptoNote::JsonRpcServer {
public:
PaymentServiceJsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, WalletService& service, Logging::ILogger& loggerGroup);
PaymentServiceJsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, WalletService& service, Logging::ILogger& loggerGroup, PaymentService::Configuration& config);
PaymentServiceJsonRpcServer(const PaymentServiceJsonRpcServer&) = delete;
protected:
@@ -290,7 +290,7 @@ void PaymentGateService::runWalletService(const CryptoNote::Currency& currency,
std::cout << "Address: " << address << std::endl;
}
} else {
PaymentService::PaymentServiceJsonRpcServer rpcServer(*dispatcher, *stopEvent, *service, logger);
PaymentService::PaymentServiceJsonRpcServer rpcServer(*dispatcher, *stopEvent, *service, logger, config.gateConfiguration);
rpcServer.start(config.gateConfiguration.bindAddress, config.gateConfiguration.bindPort);
Logging::LoggerRef(logger, "PaymentGateService")(Logging::INFO, Logging::BRIGHT_WHITE) << "JSON-RPC server stopped, stopping wallet service...";
@@ -42,12 +42,16 @@ Configuration::Configuration() {
bindPort = 0;
secretViewKey = "";
secretSpendKey = "";
rpcPassword = "";
legacySecurity = false;
}
void Configuration::initOptions(boost::program_options::options_description& desc) {
desc.add_options()
("bind-address", po::value<std::string>()->default_value("0.0.0.0"), "payment service bind address")
("bind-port", po::value<uint16_t>()->default_value(8070), "payment service bind port")
("rpc-password", po::value<std::string>(), "Specify the password to access the rpc server.")
("rpc-legacy-security", "Enable legacy mode (no password for RPC). WARNING: INSECURE. USE ONLY AS A LAST RESORT.")
("container-file,w", po::value<std::string>(), "container file")
("container-password,p", po::value<std::string>(), "container password")
("generate-container,g", "generate new container file with one wallet and exit")
@@ -152,6 +156,24 @@ void Configuration::init(const boost::program_options::variables_map& options) {
throw ConfigurationError("container-file parameter are required");
}
}
// If generating a container skip the authentication parameters.
if (generateNewContainer) {
return;
}
// Check for the authentication parameters
if ((options.count("rpc-password") == 0) && (options.count("rpc-legacy-security") == 0)) {
throw ConfigurationError("Please specify an RPC password or use the --rpc-legacy-security flag.");
}
if (options.count("rpc-legacy-security") != 0) {
legacySecurity = true;
}
else {
rpcPassword = options["rpc-password"].as<std::string>();
}
}
} //namespace PaymentService
@@ -38,6 +38,7 @@ struct Configuration {
std::string bindAddress;
uint16_t bindPort;
std::string rpcPassword;
std::string containerFile;
std::string containerPassword;
@@ -53,6 +54,7 @@ struct Configuration {
bool testnet;
bool printAddresses;
bool syncFromZero;
bool legacySecurity;
size_t logLevel;
};
@@ -31,6 +31,7 @@ JsonRpcError::JsonRpcError(int c) : code(c) {
case errMethodNotFound: message = "Method not found"; break;
case errInvalidParams: message = "Invalid params"; break;
case errInternalError: message = "Internal error"; break;
case errInvalidPassword: message = "Invalid or no password supplied"; break;
default: message = "Unknown error"; break;
}
}
@@ -37,6 +37,7 @@ const int errInvalidRequest = -32600;
const int errMethodNotFound = -32601;
const int errInvalidParams = -32602;
const int errInternalError = -32603;
const int errInvalidPassword = -32604;
class JsonRpcError: public std::exception {
public:
@@ -62,6 +63,7 @@ class JsonRpcError: public std::exception {
};
typedef boost::optional<Common::JsonValue> OptionalId;
typedef boost::optional<Common::JsonValue> OptionalPassword;
class JsonRpcRequest {
public:
@@ -84,6 +86,10 @@ class JsonRpcRequest {
if (psReq.contains("id")) {
id = psReq("id");
}
if (psReq.contains("password")) {
password = psReq("password");
}
return true;
}
@@ -112,6 +118,10 @@ class JsonRpcRequest {
const OptionalId& getId() const {
return id;
}
const OptionalPassword& getPassword() const {
return password;
}
std::string getBody() {
psReq.set("jsonrpc", std::string("2.0"));
@@ -123,6 +133,7 @@ class JsonRpcRequest {
Common::JsonValue psReq;
OptionalId id;
OptionalPassword password;
std::string method;
};
@@ -1329,6 +1329,18 @@ int main(int argc, char* argv[]) {
if (command_line::has_arg(vm, Tools::wallet_rpc_server::arg_rpc_bind_port)) {
//runs wallet with rpc interface
/*
If the rpc interface is run, ensure that either legacy mode or an RPC
password is set.
*/
if (!command_line::has_arg(vm, Tools::wallet_rpc_server::arg_rpc_password) &&
!command_line::has_arg(vm, Tools::wallet_rpc_server::arg_rpc_legacy_security)) {
logger(ERROR, BRIGHT_RED) << "Required RPC password is not set.";
return 1;
}
if (!command_line::has_arg(vm, arg_wallet_file)) {
logger(ERROR, BRIGHT_RED) << "Wallet file not set.";
return 1;
@@ -36,11 +36,16 @@ namespace Tools {
const command_line::arg_descriptor<uint16_t> wallet_rpc_server::arg_rpc_bind_port = { "rpc-bind-port", "Starts wallet as rpc server for wallet operations, sets bind port for server", 0, true };
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_ip = { "rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1" };
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_password = { "rpc-password", "Specify the password to access the rpc server.", "", true };
const command_line::arg_descriptor<bool> wallet_rpc_server::arg_rpc_legacy_security = { "rpc-legacy-security", "Enable legacy mode (no password for RPC). WARNING: INSECURE. USE ONLY AS A LAST RESORT.", false};
const command_line::arg_descriptor<bool> arg_allow_extended_rpc = {"allow-extended-rpc", "Allow RPC access to the wallet address and view/spend keys", false};
void wallet_rpc_server::init_options(boost::program_options::options_description& desc) {
command_line::add_arg(desc, arg_rpc_bind_ip);
command_line::add_arg(desc, arg_rpc_bind_port);
command_line::add_arg(desc, arg_rpc_password);
command_line::add_arg(desc, arg_rpc_legacy_security);
command_line::add_arg(desc, arg_allow_extended_rpc);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -80,6 +85,10 @@ void wallet_rpc_server::send_stop_signal() {
bool wallet_rpc_server::handle_command_line(const boost::program_options::variables_map& vm) {
m_bind_ip = command_line::get_arg(vm, arg_rpc_bind_ip);
m_port = command_line::get_arg(vm, arg_rpc_bind_port);
m_legacy = command_line::get_arg(vm, arg_rpc_legacy_security);
if (!m_legacy) {
m_password = command_line::get_arg(vm, arg_rpc_password);
}
m_allow_extended_rpc = command_line::get_arg(vm, arg_allow_extended_rpc);
return true;
}
@@ -99,10 +108,25 @@ void wallet_rpc_server::processRequest(const CryptoNote::HttpRequest& request, C
JsonRpcRequest jsonRequest;
JsonRpcResponse jsonResponse;
std::string clientPassword;
try {
jsonRequest.parseRequest(request.getBody());
jsonResponse.setId(jsonRequest.getId());
if (!m_legacy) {
const JsonRpc::OptionalPassword& clientPasswordObject = jsonRequest.getPassword();
if (!clientPasswordObject.is_initialized()) {
throw JsonRpcError(errInvalidPassword);
}
if (!clientPasswordObject.get().isString()) {
throw JsonRpcError(errInvalidPassword);
}
clientPassword = clientPasswordObject.get().getString();
if (clientPassword != m_password) {
throw JsonRpcError(errInvalidPassword);
}
}
static std::unordered_map<std::string, JsonMemberMethod> s_methods = {
{ "getbalance", makeMemberMethod(&wallet_rpc_server::on_getbalance) },
@@ -53,6 +53,8 @@ namespace Tools
static const command_line::arg_descriptor<uint16_t> arg_rpc_bind_port;
static const command_line::arg_descriptor<std::string> arg_rpc_bind_ip;
static const command_line::arg_descriptor<std::string> arg_rpc_password;
static const command_line::arg_descriptor<bool> arg_rpc_legacy_security;
private:
@@ -77,7 +79,9 @@ namespace Tools
CryptoNote::INode& m_node;
uint16_t m_port;
bool m_allow_extended_rpc;
bool m_legacy;
std::string m_bind_ip;
std::string m_password;
CryptoNote::Currency& m_currency;
const std::string m_walletFilename;

3 comments on commit 4949e91

@jared201

This comment has been minimized.

jared201 replied Feb 12, 2018

anyone tested it?

@RocksteadyTC

This comment has been minimized.

Contributor

RocksteadyTC replied Feb 12, 2018

@jared201 Yes, it is now in production 0.3.2

@jared201

This comment has been minimized.

jared201 replied Feb 12, 2018

thanks! any curl samples?

Please sign in to comment.