mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-23 04:25:51 +00:00
Changes to Universal Port:
* Add tests * Introduce requestRole helper * Always honor admin=no * Welcome guests anywhere admin privileges aren't required
This commit is contained in:
committed by
Tom Ritchford
parent
aaf98082e9
commit
91871b418b
@@ -11,6 +11,7 @@
|
|||||||
"async": "~0.2.9",
|
"async": "~0.2.9",
|
||||||
"deep-equal": "0.0.0",
|
"deep-equal": "0.0.0",
|
||||||
"extend": "~1.2.0",
|
"extend": "~1.2.0",
|
||||||
|
"request": "^2.47.0",
|
||||||
"ripple-lib": "0.10.0",
|
"ripple-lib": "0.10.0",
|
||||||
"simple-jsonrpc": "~0.0.2"
|
"simple-jsonrpc": "~0.0.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <ripple/protocol/JsonFields.h>
|
#include <ripple/protocol/JsonFields.h>
|
||||||
#include <ripple/resource/Fees.h>
|
#include <ripple/resource/Fees.h>
|
||||||
#include <ripple/server/Role.h>
|
#include <ripple/server/Role.h>
|
||||||
|
#include <ripple/rpc/RPCHandler.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -163,8 +164,11 @@ Json::Value WSConnection::invokeCommand (Json::Value& jvRequest)
|
|||||||
Resource::Charge loadType = Resource::feeReferenceRPC;
|
Resource::Charge loadType = Resource::feeReferenceRPC;
|
||||||
Json::Value jvResult (Json::objectValue);
|
Json::Value jvResult (Json::objectValue);
|
||||||
|
|
||||||
Role const role = port_.allow_admin ? adminRole (port_, jvRequest,
|
Role const required = RPC::roleRequired (
|
||||||
m_remoteAddress, getConfig().RPC_ADMIN_ALLOW) : Role::GUEST;
|
jvRequest[jss::command].asString());
|
||||||
|
|
||||||
|
Role const role = requestRole (required, port_, jvRequest, m_remoteAddress,
|
||||||
|
getConfig().RPC_ADMIN_ALLOW);
|
||||||
|
|
||||||
if (Role::FORBID == role)
|
if (Role::FORBID == role)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,8 +37,7 @@ Status doCommand (RPC::Context&, Json::Value&, YieldStrategy const& s = {});
|
|||||||
/** Execute an RPC command and store the results in an std::string. */
|
/** Execute an RPC command and store the results in an std::string. */
|
||||||
void executeRPC (RPC::Context&, std::string&, YieldStrategy const& s = {});
|
void executeRPC (RPC::Context&, std::string&, YieldStrategy const& s = {});
|
||||||
|
|
||||||
/** Temporary flag to enable RPCs. */
|
Role roleRequired (std::string const& method );
|
||||||
auto const streamingRPC = false;
|
|
||||||
|
|
||||||
} // RPC
|
} // RPC
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -254,5 +254,15 @@ void executeRPC (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Role roleRequired (std::string const& method)
|
||||||
|
{
|
||||||
|
auto handler = RPC::getHandler(method);
|
||||||
|
|
||||||
|
if (!handler)
|
||||||
|
return Role::FORBID;
|
||||||
|
|
||||||
|
return handler->role_;
|
||||||
|
}
|
||||||
|
|
||||||
} // RPC
|
} // RPC
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ enum class Role
|
|||||||
validate the credentials.
|
validate the credentials.
|
||||||
*/
|
*/
|
||||||
Role
|
Role
|
||||||
adminRole (HTTP::Port const& port, Json::Value const& jsonRPC,
|
requestRole (Role const& required, HTTP::Port const& port,
|
||||||
beast::IP::Endpoint const& remoteIp,
|
Json::Value const& jsonRPC, beast::IP::Endpoint const& remoteIp,
|
||||||
std::vector<beast::IP::Endpoint> const& admin_allow);
|
std::vector<beast::IP::Endpoint> const& admin_allow);
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -22,72 +22,48 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
Role
|
bool
|
||||||
adminRole (HTTP::Port const& port, Json::Value const& params,
|
passwordUnrequiredOrSentCorrect (HTTP::Port const& port,
|
||||||
beast::IP::Endpoint const& remoteIp,
|
Json::Value const& params) {
|
||||||
std::vector<beast::IP::Endpoint> const& admin_allow)
|
|
||||||
|
assert(port.allow_admin);
|
||||||
|
bool const passwordRequired = (!port.admin_user.empty() ||
|
||||||
|
!port.admin_password.empty());
|
||||||
|
|
||||||
|
return !passwordRequired ||
|
||||||
|
((params["admin_password"].isString() &&
|
||||||
|
params["admin_password"].asString() == port.admin_password) &&
|
||||||
|
(params["admin_user"].isString() &&
|
||||||
|
params["admin_user"].asString() == port.admin_user));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ipAllowed (beast::IP::Endpoint const& remoteIp,
|
||||||
|
std::vector<beast::IP::Endpoint> const& adminAllow)
|
||||||
{
|
{
|
||||||
Role role (Role::FORBID);
|
return std::find(adminAllow.begin(), adminAllow.end(),
|
||||||
|
remoteIp.at_port(0)) != adminAllow.end();
|
||||||
|
}
|
||||||
|
|
||||||
bool const bPasswordSupplied =
|
bool
|
||||||
params.isMember ("admin_user") ||
|
isAdmin (HTTP::Port const& port, Json::Value const& params,
|
||||||
params.isMember ("admin_password");
|
beast::IP::Endpoint const& remoteIp,
|
||||||
|
std::vector<beast::IP::Endpoint> const& adminAllow)
|
||||||
bool const bPasswordRequired =
|
{
|
||||||
! port.admin_user.empty() || ! port.admin_password.empty();
|
return (port.allow_admin && ipAllowed(remoteIp, adminAllow)) &&
|
||||||
|
passwordUnrequiredOrSentCorrect(port, params);
|
||||||
bool bPasswordWrong;
|
}
|
||||||
|
|
||||||
if (bPasswordSupplied)
|
|
||||||
{
|
|
||||||
if (bPasswordRequired)
|
|
||||||
{
|
|
||||||
// Required, and supplied, check match
|
|
||||||
bPasswordWrong =
|
|
||||||
(port.admin_user !=
|
|
||||||
(params.isMember ("admin_user") ? params["admin_user"].asString () : ""))
|
|
||||||
||
|
|
||||||
(port.admin_password !=
|
|
||||||
(params.isMember ("admin_user") ? params["admin_password"].asString () : ""));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Not required, but supplied
|
|
||||||
bPasswordWrong = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Required but not supplied,
|
|
||||||
bPasswordWrong = bPasswordRequired;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Meets IP restriction for admin.
|
|
||||||
beast::IP::Endpoint const remote_addr (remoteIp.at_port (0));
|
|
||||||
bool bAdminIP = false;
|
|
||||||
|
|
||||||
// VFALCO TODO Don't use this!
|
|
||||||
for (auto const& allow_addr : admin_allow)
|
|
||||||
{
|
|
||||||
if (allow_addr == remote_addr)
|
|
||||||
{
|
|
||||||
bAdminIP = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bPasswordWrong // Wrong
|
|
||||||
|| (bPasswordSupplied && !bAdminIP)) // Supplied and doesn't meet IP filter.
|
|
||||||
{
|
|
||||||
role = Role::FORBID;
|
|
||||||
}
|
|
||||||
// If supplied, password is correct.
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Allow admin, if from admin IP and no password is required or it was supplied and correct.
|
|
||||||
role = bAdminIP && (!bPasswordRequired || bPasswordSupplied) ? Role::ADMIN : Role::GUEST;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Role
|
||||||
|
requestRole (Role const& required, HTTP::Port const& port,
|
||||||
|
Json::Value const& params, beast::IP::Endpoint const& remoteIp,
|
||||||
|
std::vector<beast::IP::Endpoint> const& adminAllow)
|
||||||
|
{
|
||||||
|
Role role (Role::GUEST);
|
||||||
|
if (isAdmin(port, params, remoteIp, adminAllow))
|
||||||
|
role = Role::ADMIN;
|
||||||
|
if (required == Role::ADMIN && role != required)
|
||||||
|
role = Role::FORBID;
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#include <ripple/resource/Fees.h>
|
#include <ripple/resource/Fees.h>
|
||||||
#include <ripple/rpc/Coroutine.h>
|
#include <ripple/rpc/Coroutine.h>
|
||||||
#include <beast/crypto/base64.h>
|
#include <beast/crypto/base64.h>
|
||||||
#include <ripple/rpc/RPCHandler.h>
|
#include <ripple/rpc/RPCHandler.h>
|
||||||
#include <beast/cxx14/algorithm.h> // <algorithm>
|
#include <beast/cxx14/algorithm.h> // <algorithm>
|
||||||
#include <beast/http/rfc2616.h>
|
#include <beast/http/rfc2616.h>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
@@ -283,16 +283,41 @@ ServerHandlerImp::processRequest (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse id now so errors from here on will have the id
|
||||||
|
//
|
||||||
|
// VFALCO NOTE Except that "id" isn't included in the following errors.
|
||||||
|
//
|
||||||
|
Json::Value const& id = jsonRPC ["id"];
|
||||||
|
|
||||||
|
Json::Value const& method = jsonRPC ["method"];
|
||||||
|
|
||||||
|
if (method.isNull ()) {
|
||||||
|
HTTPReply (400, "Null method", output);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!method.isString ()) {
|
||||||
|
HTTPReply (400, "method is not string", output);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
auto const& admin_allow = getConfig().RPC_ADMIN_ALLOW;
|
auto const& admin_allow = getConfig().RPC_ADMIN_ALLOW;
|
||||||
auto role = Role::FORBID;
|
auto role = Role::FORBID;
|
||||||
if (jsonRPC.isObject() && jsonRPC.isMember(jss::params) &&
|
auto required = RPC::roleRequired(id.asString());
|
||||||
jsonRPC[jss::params].isArray() && jsonRPC[jss::params].size() > 0 &&
|
|
||||||
jsonRPC[jss::params][Json::UInt(0)].isObject())
|
if (jsonRPC.isObject() && jsonRPC.isMember("params") &&
|
||||||
role = adminRole(port, jsonRPC[jss::params][Json::UInt(0)],
|
jsonRPC["params"].isArray() && jsonRPC["params"].size() > 0 &&
|
||||||
|
jsonRPC["params"][Json::UInt(0)].isObject())
|
||||||
|
{
|
||||||
|
role = requestRole(required, port, jsonRPC["params"][Json::UInt(0)],
|
||||||
remoteIPAddress, admin_allow);
|
remoteIPAddress, admin_allow);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
role = adminRole(port, Json::objectValue,
|
{
|
||||||
|
role = requestRole(required, port, Json::objectValue,
|
||||||
remoteIPAddress, admin_allow);
|
remoteIPAddress, admin_allow);
|
||||||
|
}
|
||||||
|
|
||||||
Resource::Consumer usage;
|
Resource::Consumer usage;
|
||||||
|
|
||||||
@@ -307,25 +332,6 @@ ServerHandlerImp::processRequest (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse id now so errors from here on will have the id
|
|
||||||
//
|
|
||||||
// VFALCO NOTE Except that "id" isn't included in the following errors.
|
|
||||||
//
|
|
||||||
Json::Value const id = jsonRPC ["id"];
|
|
||||||
Json::Value const method = jsonRPC ["method"];
|
|
||||||
|
|
||||||
if (method.isNull ())
|
|
||||||
{
|
|
||||||
HTTPReply (400, "Null method", output);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! method.isString ())
|
|
||||||
{
|
|
||||||
HTTPReply (400, "method is not string", output);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string strMethod = method.asString ();
|
std::string strMethod = method.asString ();
|
||||||
if (strMethod.empty())
|
if (strMethod.empty())
|
||||||
{
|
{
|
||||||
@@ -419,7 +425,7 @@ ServerHandlerImp::processRequest (
|
|||||||
context.metrics.fetches));
|
context.metrics.fetches));
|
||||||
rpc_size_.notify (static_cast <beast::insight::Event::value_type> (
|
rpc_size_.notify (static_cast <beast::insight::Event::value_type> (
|
||||||
response.size ()));
|
response.size ()));
|
||||||
|
|
||||||
response += '\n';
|
response += '\n';
|
||||||
usage.charge (loadType);
|
usage.charge (loadType);
|
||||||
|
|
||||||
@@ -479,76 +485,6 @@ ServerHandlerImp::onWrite (beast::PropertyStream::Map& map)
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Copied from Config::getAdminRole and modified to use the Port
|
|
||||||
Role
|
|
||||||
adminRole (HTTP::Port const& port,
|
|
||||||
Json::Value const& params, beast::IP::Endpoint const& remoteIp)
|
|
||||||
{
|
|
||||||
Role role (Role::FORBID);
|
|
||||||
|
|
||||||
bool const bPasswordSupplied =
|
|
||||||
params.isMember ("admin_user") ||
|
|
||||||
params.isMember ("admin_password");
|
|
||||||
|
|
||||||
bool const bPasswordRequired =
|
|
||||||
! port.admin_user.empty() || ! port.admin_password.empty();
|
|
||||||
|
|
||||||
bool bPasswordWrong;
|
|
||||||
|
|
||||||
if (bPasswordSupplied)
|
|
||||||
{
|
|
||||||
if (bPasswordRequired)
|
|
||||||
{
|
|
||||||
// Required, and supplied, check match
|
|
||||||
bPasswordWrong =
|
|
||||||
(port.admin_user !=
|
|
||||||
(params.isMember ("admin_user") ? params["admin_user"].asString () : ""))
|
|
||||||
||
|
|
||||||
(port.admin_password !=
|
|
||||||
(params.isMember ("admin_user") ? params["admin_password"].asString () : ""));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Not required, but supplied
|
|
||||||
bPasswordWrong = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Required but not supplied,
|
|
||||||
bPasswordWrong = bPasswordRequired;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Meets IP restriction for admin.
|
|
||||||
beast::IP::Endpoint const remote_addr (remoteIp.at_port (0));
|
|
||||||
bool bAdminIP = false;
|
|
||||||
|
|
||||||
for (auto const& allow_addr : getConfig().RPC_ADMIN_ALLOW)
|
|
||||||
{
|
|
||||||
if (allow_addr == remote_addr)
|
|
||||||
{
|
|
||||||
bAdminIP = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bPasswordWrong // Wrong
|
|
||||||
|| (bPasswordSupplied && !bAdminIP)) // Supplied and doesn't meet IP filter.
|
|
||||||
{
|
|
||||||
role = Role::FORBID;
|
|
||||||
}
|
|
||||||
// If supplied, password is correct.
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Allow admin, if from admin IP and no password is required or it was supplied and correct.
|
|
||||||
role = bAdminIP && (!bPasswordRequired || bPasswordSupplied) ? Role::ADMIN : Role::GUEST;
|
|
||||||
}
|
|
||||||
|
|
||||||
return role;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ServerHandler::appendStandardFields (beast::http::message& message)
|
ServerHandler::appendStandardFields (beast::http::message& message)
|
||||||
{
|
{
|
||||||
@@ -841,7 +777,7 @@ setup_ServerHandler (BasicConfig const& config, std::ostream& log)
|
|||||||
|
|
||||||
std::unique_ptr <ServerHandler>
|
std::unique_ptr <ServerHandler>
|
||||||
make_ServerHandler (beast::Stoppable& parent,
|
make_ServerHandler (beast::Stoppable& parent,
|
||||||
boost::asio::io_service& io_service, JobQueue& jobQueue,
|
boost::asio::io_service& io_service, JobQueue& jobQueue,
|
||||||
NetworkOPs& networkOPs, Resource::Manager& resourceManager,
|
NetworkOPs& networkOPs, Resource::Manager& resourceManager,
|
||||||
CollectorManager& cm)
|
CollectorManager& cm)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#if DOXYGEN
|
#if DOXYGEN
|
||||||
#include <ripple/server/README.md>
|
#include <ripple/server/README.md>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,10 +2,27 @@
|
|||||||
// Configuration for unit tests: to be locally customized as needed.
|
// Configuration for unit tests: to be locally customized as needed.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
var extend = require('extend');
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var extend = require('extend');
|
var extend = require('extend');
|
||||||
var testconfig = require("./testconfig.js");
|
var testconfig = require("./testconfig.js");
|
||||||
|
|
||||||
|
//
|
||||||
|
// Helpers
|
||||||
|
//
|
||||||
|
|
||||||
|
function lines () {
|
||||||
|
return Array.prototype.slice.call(arguments).join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
function for_each_item (o, f) {
|
||||||
|
for (var k in o) {
|
||||||
|
if (o.hasOwnProperty(k)) {
|
||||||
|
f(k, o[k], o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
exports.accounts = testconfig.accounts;
|
exports.accounts = testconfig.accounts;
|
||||||
|
|
||||||
exports.server_default = "alpha";
|
exports.server_default = "alpha";
|
||||||
@@ -21,8 +38,6 @@ exports.default_server_config = {
|
|||||||
// For testing, you might choose to target a persistent server at alternate ports.
|
// For testing, you might choose to target a persistent server at alternate ports.
|
||||||
//
|
//
|
||||||
|
|
||||||
var lines = function() {return Array.prototype.slice.call(arguments).join('\n')}
|
|
||||||
|
|
||||||
exports.servers = {
|
exports.servers = {
|
||||||
// A local test server.
|
// A local test server.
|
||||||
"alpha" : {
|
"alpha" : {
|
||||||
@@ -58,6 +73,20 @@ exports.servers = {
|
|||||||
|
|
||||||
'node_db': lines('type=memory',
|
'node_db': lines('type=memory',
|
||||||
'path=integration')
|
'path=integration')
|
||||||
|
},
|
||||||
|
|
||||||
|
'uniport_tests' : {
|
||||||
|
// rippled.cfg
|
||||||
|
'node_db': lines('type=memory', 'path=integration'),
|
||||||
|
|
||||||
|
// We let testutils.build_setup connect normally, and use the Remote to
|
||||||
|
// determine when the server is ready, so we must configure it, even though
|
||||||
|
// we don't otherwise use it in the test.
|
||||||
|
'websocket_ip': "127.0.0.1",
|
||||||
|
'websocket_port': 6432,
|
||||||
|
'websocket_ssl': false,
|
||||||
|
'trusted' : true,
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -66,6 +95,71 @@ exports.servers.debug = extend({
|
|||||||
debug_logfile: "debug.log"
|
debug_logfile: "debug.log"
|
||||||
}, exports.servers.alpha);
|
}, exports.servers.alpha);
|
||||||
|
|
||||||
|
exports.uniport_test_ports = {
|
||||||
|
'port_admin_http':
|
||||||
|
{'admin': 'allow', 'port': 6434, 'protocol': 'http'},
|
||||||
|
'port_admin_http_and_https':
|
||||||
|
{'admin': 'allow', 'port': 6437, 'protocol': 'http,https'},
|
||||||
|
'port_admin_https':
|
||||||
|
{'admin': 'allow', 'port': 6435, 'protocol': 'https'},
|
||||||
|
'port_admin_ws':
|
||||||
|
{'admin': 'allow', 'port': 6432, 'protocol': 'ws'},
|
||||||
|
'port_admin_ws_and_wss':
|
||||||
|
{'admin': 'allow', 'port': 6436, 'protocol': 'ws,wss'},
|
||||||
|
'port_admin_wss':
|
||||||
|
{'admin': 'allow', 'port': 6433, 'protocol': 'wss'},
|
||||||
|
|
||||||
|
'port_http':
|
||||||
|
{'admin': 'no', 'port': 6440, 'protocol': 'http'},
|
||||||
|
'port_http_and_https':
|
||||||
|
{'admin': 'no', 'port': 6443, 'protocol': 'http,https'},
|
||||||
|
'port_https':
|
||||||
|
{'admin': 'no', 'port': 6441, 'protocol': 'https'},
|
||||||
|
'port_https_and_http_and_peer':
|
||||||
|
{'admin': 'no', 'port': 6450, 'protocol': 'https,peer,http'},
|
||||||
|
|
||||||
|
'port_passworded_admin_http':
|
||||||
|
{'admin': 'allow', 'admin_password': 'p', 'admin_user': 'u',
|
||||||
|
'port': 6446, 'protocol': 'http'},
|
||||||
|
'port_passworded_admin_http_and_https':
|
||||||
|
{'admin': 'allow', 'admin_password': 'p', 'admin_user': 'u',
|
||||||
|
'port': 6449, 'protocol': 'http,https'},
|
||||||
|
'port_passworded_admin_https':
|
||||||
|
{'admin': 'allow', 'admin_password': 'p', 'admin_user': 'u',
|
||||||
|
'port': 6447, 'protocol': 'https'},
|
||||||
|
'port_passworded_admin_ws':
|
||||||
|
{'admin': 'allow', 'admin_password': 'p', 'admin_user': 'u',
|
||||||
|
'port': 6444, 'protocol': 'ws'},
|
||||||
|
'port_passworded_admin_ws_and_wss':
|
||||||
|
{'admin': 'allow', 'admin_password': 'p', 'admin_user': 'u',
|
||||||
|
'port': 6448, 'protocol': 'ws,wss'},
|
||||||
|
'port_passworded_admin_wss':
|
||||||
|
{'admin': 'allow', 'admin_password': 'p', 'admin_user': 'u',
|
||||||
|
'port': 6445, 'protocol': 'wss'},
|
||||||
|
|
||||||
|
'port_ws':
|
||||||
|
{'admin': 'no', 'port': 6438, 'protocol': 'ws'},
|
||||||
|
'port_ws_and_wss':
|
||||||
|
{'admin': 'no', 'port': 6442, 'protocol': 'ws,wss'},
|
||||||
|
'port_wss':
|
||||||
|
{'admin': 'no', 'port': 6439, 'protocol': 'wss'}
|
||||||
|
};
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var server_config = exports.servers.uniport_tests;
|
||||||
|
var test_ports = exports.uniport_test_ports;
|
||||||
|
|
||||||
|
// [server]
|
||||||
|
server_config.server = Object.keys(test_ports).join('\n');
|
||||||
|
|
||||||
|
// [port_*]
|
||||||
|
for_each_item(test_ports, function(port_name, options) {
|
||||||
|
var opt_line = ['ip=127.0.0.1'];
|
||||||
|
for_each_item(options, function(k, v) {opt_line.push(k+'='+v);});
|
||||||
|
server_config[port_name] = opt_line.join('\n');
|
||||||
|
});
|
||||||
|
}());
|
||||||
|
|
||||||
exports.http_servers = {
|
exports.http_servers = {
|
||||||
// A local test server
|
// A local test server
|
||||||
"zed" : {
|
"zed" : {
|
||||||
|
|||||||
@@ -69,6 +69,33 @@ function prepare_tests(tests, fn) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.definer_matching = function(matchers, def) {
|
||||||
|
return function (name, func)
|
||||||
|
{
|
||||||
|
var definer = def;
|
||||||
|
var skip_if_not_match = matchers.skip_if_not_match || [];
|
||||||
|
var skip_if_match = matchers.skip_if_match || [];
|
||||||
|
|
||||||
|
for (var i = 0; i < skip_if_not_match.length; i++) {
|
||||||
|
var regex = skip_if_not_match[i];
|
||||||
|
if (!~name.search(regex)) {
|
||||||
|
definer = definer.skip;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < skip_if_match.length; i++) {
|
||||||
|
var regex = skip_if_match[i];
|
||||||
|
if (~name.search(regex)) {
|
||||||
|
definer = definer.skip;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
definer(name, func);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper called by test cases to generate a setUp routine.
|
* Helper called by test cases to generate a setUp routine.
|
||||||
*
|
*
|
||||||
@@ -101,7 +128,7 @@ function build_setup(opts, host) {
|
|||||||
if (opts.verbose) {
|
if (opts.verbose) {
|
||||||
opts.verbose_ws = true;
|
opts.verbose_ws = true;
|
||||||
opts.verbose_server = true;
|
opts.verbose_server = true;
|
||||||
};
|
}
|
||||||
|
|
||||||
function setup(done) {
|
function setup(done) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -113,7 +140,7 @@ function build_setup(opts, host) {
|
|||||||
|
|
||||||
self.amount_for = function(options) {
|
self.amount_for = function(options) {
|
||||||
var reserve = self.remote.reserve(options.ledger_entries || 0);
|
var reserve = self.remote.reserve(options.ledger_entries || 0);
|
||||||
var fees = self.compute_fees_amount_for_txs(options.default_transactions || 0)
|
var fees = self.compute_fees_amount_for_txs(options.default_transactions || 0);
|
||||||
return reserve.add(fees).add(options.extra || 0);
|
return reserve.add(fees).add(options.extra || 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -136,7 +163,7 @@ function build_setup(opts, host) {
|
|||||||
// Setting undefined is a noop here
|
// Setting undefined is a noop here
|
||||||
if (data.opts.ledger_file != null) {
|
if (data.opts.ledger_file != null) {
|
||||||
data.server.set_ledger_file(data.opts.ledger_file);
|
data.server.set_ledger_file(data.opts.ledger_file);
|
||||||
};
|
}
|
||||||
|
|
||||||
data.server.once('started', function() {
|
data.server.once('started', function() {
|
||||||
callback();
|
callback();
|
||||||
@@ -159,8 +186,6 @@ function build_setup(opts, host) {
|
|||||||
|
|
||||||
function connect_websocket(callback) {
|
function connect_websocket(callback) {
|
||||||
self.remote = data.remote = Remote.from_config(host, !!opts.verbose_ws);
|
self.remote = data.remote = Remote.from_config(host, !!opts.verbose_ws);
|
||||||
|
|
||||||
// TODO:
|
|
||||||
self.remote.once('connected', function() {
|
self.remote.once('connected', function() {
|
||||||
// self.remote.once('ledger_closed', function() {
|
// self.remote.once('ledger_closed', function() {
|
||||||
callback();
|
callback();
|
||||||
@@ -625,7 +650,8 @@ exports.verify_owner_count = verify_owner_count;
|
|||||||
exports.verify_owner_counts = verify_owner_counts;
|
exports.verify_owner_counts = verify_owner_counts;
|
||||||
exports.ledger_wait = ledger_wait;
|
exports.ledger_wait = ledger_wait;
|
||||||
|
|
||||||
process.on('uncaughtException', function() {
|
// Close up all unclosed servers on exit.
|
||||||
|
process.on('exit', function() {
|
||||||
Object.keys(server).forEach(function(host) {
|
Object.keys(server).forEach(function(host) {
|
||||||
server[host].stop();
|
server[host].stop();
|
||||||
});
|
});
|
||||||
|
|||||||
492
test/uniport-tests.js
Normal file
492
test/uniport-tests.js
Normal file
@@ -0,0 +1,492 @@
|
|||||||
|
/* -------------------------------- REQUIRES -------------------------------- */
|
||||||
|
|
||||||
|
var async = require("async");
|
||||||
|
var assert = require('assert');
|
||||||
|
var assert = require('assert');
|
||||||
|
var UInt160 = require("ripple-lib").UInt160;
|
||||||
|
var Remote = require('ripple-lib').Remote;
|
||||||
|
var Server = require('ripple-lib').Server;
|
||||||
|
var Request = require('ripple-lib').Request;
|
||||||
|
var testutils = require("./testutils");
|
||||||
|
var config = testutils.init_config();
|
||||||
|
var http = require('http');
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
|
/* --------------------------------- CONFIG --------------------------------- */
|
||||||
|
|
||||||
|
// So we can connect to the ports with self signed certificates.
|
||||||
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||||
|
|
||||||
|
var uniport_test_config = {
|
||||||
|
// We have one main WebSocket connection that we inherit from
|
||||||
|
// `testutils.build_setup`. We use that, configured on a non admin, non ssl
|
||||||
|
// port, to determine readiness for tests on the other ports. This Remote's
|
||||||
|
// trace is configured in the normal way, however we can set trace for each of
|
||||||
|
// the test connections on the various ports.
|
||||||
|
remote_trace : false,
|
||||||
|
|
||||||
|
// We can be a bit more exhaustive, but it will cost us 2 seconds, unless
|
||||||
|
// we use `skip_tests_matching` to `test.skip` them.
|
||||||
|
define_redundant_tests : false,
|
||||||
|
|
||||||
|
skip_tests_matching : [
|
||||||
|
// /redundant/
|
||||||
|
|
||||||
|
// /can not issue/,
|
||||||
|
// /http/
|
||||||
|
],
|
||||||
|
|
||||||
|
skip_tests_not_matching : [
|
||||||
|
// /wrong password/,
|
||||||
|
// /ws/
|
||||||
|
],
|
||||||
|
|
||||||
|
skip_ports_not_matching : [
|
||||||
|
// /admin/,
|
||||||
|
// /password/,
|
||||||
|
// /http/
|
||||||
|
],
|
||||||
|
|
||||||
|
skip_ports_matching : [
|
||||||
|
// /admin/,
|
||||||
|
// /password/,
|
||||||
|
// /http/
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
/* --------------------------------- HELPERS -------------------------------- */
|
||||||
|
|
||||||
|
function for_each_item (o, f) {
|
||||||
|
for (var k in o) {
|
||||||
|
if (o.hasOwnProperty(k)) {
|
||||||
|
f(k, o[k], o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function pretty_json (o) {
|
||||||
|
return JSON.stringify(o, undefined, 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
function client_protocols (conf) {
|
||||||
|
return conf.protocol.split(',').filter(function (p) {return p !== 'peer';});
|
||||||
|
};
|
||||||
|
|
||||||
|
function same_protocol_opposite_security (protocol) {
|
||||||
|
switch(protocol)
|
||||||
|
{
|
||||||
|
case 'ws':
|
||||||
|
return 'wss';
|
||||||
|
case 'http':
|
||||||
|
return 'https';
|
||||||
|
case 'wss':
|
||||||
|
return 'ws';
|
||||||
|
case 'https':
|
||||||
|
return 'http';
|
||||||
|
default:
|
||||||
|
throw new Error('unknown protocol '+ protocol);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function one_invocation_function (f) {
|
||||||
|
var already_done = false;
|
||||||
|
return function done_once() {
|
||||||
|
try {
|
||||||
|
if (!already_done) {
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
already_done = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function mark_redundant_tests (normalizer) {
|
||||||
|
var tested = [];
|
||||||
|
|
||||||
|
return function (test_name, func) {
|
||||||
|
var normed = normalizer ? normalizer(test_name) : test_name;
|
||||||
|
var redundant = ~tested.indexOf(normed);
|
||||||
|
|
||||||
|
if (redundant)
|
||||||
|
test_name += ' (redundant)';
|
||||||
|
else
|
||||||
|
tested.push(normed);
|
||||||
|
|
||||||
|
if (!redundant || uniport_test_config.define_redundant_tests) {
|
||||||
|
define_test(test_name, func);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function add_credentials_to_request (message, credentials, wrong_pass,
|
||||||
|
wrong_user)
|
||||||
|
{
|
||||||
|
message.admin_user = credentials.admin_user;
|
||||||
|
message.admin_password = credentials.admin_password;
|
||||||
|
|
||||||
|
if (wrong_pass) {
|
||||||
|
if (wrong_pass === 'send_object_instead_of_string') {
|
||||||
|
message.admin_password = {admin_password: message.admin_password};
|
||||||
|
} else {
|
||||||
|
message.admin_password += '_';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wrong_user) {
|
||||||
|
message.admin_user += '_';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var define_test = testutils.definer_matching(
|
||||||
|
{
|
||||||
|
skip_if_not_match:uniport_test_config.skip_tests_not_matching,
|
||||||
|
skip_if_match:uniport_test_config.skip_tests_matching
|
||||||
|
},
|
||||||
|
global.test );
|
||||||
|
|
||||||
|
var define_suite = testutils.definer_matching(
|
||||||
|
{
|
||||||
|
skip_if_not_match:uniport_test_config.skip_ports_not_matching,
|
||||||
|
skip_if_match:uniport_test_config.skip_ports_matching
|
||||||
|
},
|
||||||
|
global.suite );
|
||||||
|
|
||||||
|
/* ---------------------------------- TESTS --------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
function test_websocket_admin_command (test_declaration,
|
||||||
|
protocol,
|
||||||
|
port_conf, done)
|
||||||
|
{
|
||||||
|
var expect_success = test_declaration.expect_success;
|
||||||
|
var expect_failure = !expect_success;
|
||||||
|
var require_pass = Boolean(port_conf.admin_password);
|
||||||
|
var send_credentials = test_declaration.send_credentials;
|
||||||
|
var wrong_pass = test_declaration.wrong_pass;
|
||||||
|
var wrong_user = test_declaration.wrong_user;
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
'websocket_ip': "127.0.0.1",
|
||||||
|
'websocket_port': port_conf.port,
|
||||||
|
'websocket_ssl': protocol === 'wss',
|
||||||
|
'trace' : uniport_test_config.remote_trace
|
||||||
|
};
|
||||||
|
|
||||||
|
var remote = Remote.from_config(config);
|
||||||
|
|
||||||
|
if (require_pass) {
|
||||||
|
remote.on('prepare_subscribe', function (request){
|
||||||
|
request.once('error', function (e, m){
|
||||||
|
assert.notEqual(e.remote.error,
|
||||||
|
'forbidden',
|
||||||
|
'Need credentials for non admin request (subscribe)');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
remote.once('connected', function () {
|
||||||
|
var before_accept = remote._ledger_current_index;
|
||||||
|
var request = new Request(remote, 'ledger_accept');
|
||||||
|
|
||||||
|
if (send_credentials) {
|
||||||
|
add_credentials_to_request( request.message, port_conf,
|
||||||
|
wrong_pass, wrong_user);
|
||||||
|
}
|
||||||
|
|
||||||
|
request.request(function (error, response){
|
||||||
|
// Disconnect
|
||||||
|
remote.connect(false);
|
||||||
|
|
||||||
|
function create_error (message) {
|
||||||
|
var struct = {port_conf: port_conf,
|
||||||
|
request: request.message,
|
||||||
|
error: error,
|
||||||
|
response: response,
|
||||||
|
test_failure: message};
|
||||||
|
return pretty_json(struct);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
assert(expect_failure,
|
||||||
|
create_error('unexpect failure to issue admin command'));
|
||||||
|
|
||||||
|
if (expect_failure) {
|
||||||
|
if (require_pass && (!send_credentials || wrong_pass || wrong_user)) {
|
||||||
|
assert.equal(error.remote.error,
|
||||||
|
'forbidden',
|
||||||
|
create_error('should be forbidden'));
|
||||||
|
|
||||||
|
} else if (!require_pass) {
|
||||||
|
assert.equal(error.remote.error,
|
||||||
|
'forbidden',
|
||||||
|
create_error('should be forbidden'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
if (expect_success) {
|
||||||
|
assert.equal((before_accept + 1), response.ledger_current_index,
|
||||||
|
create_error('admin command should work but did not'));
|
||||||
|
} else {
|
||||||
|
assert.equal(before_accept, response.ledger_current_index,
|
||||||
|
create_error('admin command worked but should not have'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
remote.connect();
|
||||||
|
};
|
||||||
|
|
||||||
|
function test_http_admin_command (test_declaration, protocol, conf, done)
|
||||||
|
{
|
||||||
|
var expect_success = test_declaration.expect_success;
|
||||||
|
var expect_failure = !expect_success;
|
||||||
|
var require_pass = Boolean(conf.admin_password);
|
||||||
|
var send_credentials = test_declaration.send_credentials;
|
||||||
|
var wrong_pass = test_declaration.wrong_pass;
|
||||||
|
var wrong_user = test_declaration.wrong_user;
|
||||||
|
|
||||||
|
var url = protocol+'://localhost:'+conf.port + '/';
|
||||||
|
|
||||||
|
var post_options = {
|
||||||
|
url: url,
|
||||||
|
json: true,
|
||||||
|
body: {
|
||||||
|
method: 'ledger_accept',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (send_credentials) {
|
||||||
|
var credentials = {};
|
||||||
|
post_options.body.params = [credentials];
|
||||||
|
add_credentials_to_request(credentials, conf, wrong_pass, wrong_user);
|
||||||
|
}
|
||||||
|
|
||||||
|
request.post(post_options, function (err, response, body) {
|
||||||
|
function create_error (message) {
|
||||||
|
var struct = {port_conf: conf,
|
||||||
|
request: post_options,
|
||||||
|
error: err,
|
||||||
|
response: body,
|
||||||
|
statusCode: response.statusCode,
|
||||||
|
test_failure: message};
|
||||||
|
return pretty_json(struct);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
assert(!err, String(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expect_failure)
|
||||||
|
{
|
||||||
|
if (!body) {
|
||||||
|
assert.equal(response.statusCode, 403);
|
||||||
|
assert (false, create_error("we expect some kind of response body"));
|
||||||
|
}
|
||||||
|
else if (typeof body == 'string') {
|
||||||
|
assert.equal(response.statusCode, 403);
|
||||||
|
assert.equal(body.trim(), 'Forbidden');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(body.result.status != 'success',
|
||||||
|
create_error("succeded when shouldn't have"));
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var msg = "expected 200 got " + response.statusCode+'\n'+pretty_json(body);
|
||||||
|
assert.equal(response.statusCode, 200, msg);
|
||||||
|
|
||||||
|
if (body && body.result) {
|
||||||
|
assert.equal(body.result.status, 'success', pretty_json(body));
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function test_admin_command (test_declaration, protocol,
|
||||||
|
port_conf, done) {
|
||||||
|
|
||||||
|
var type = protocol.slice(0, 2);
|
||||||
|
if (type == 'ws') {
|
||||||
|
test_websocket_admin_command(test_declaration, protocol, port_conf, done);
|
||||||
|
}
|
||||||
|
else if (type == 'ht') {
|
||||||
|
test_http_admin_command(test_declaration, protocol, port_conf, done);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error('unknown protocol: ' + protocol);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function test_cant_connect (port_conf, protocol, done) {
|
||||||
|
var type = protocol.slice(0, 2);
|
||||||
|
|
||||||
|
if (type == 'ws') {
|
||||||
|
done_once = one_invocation_function (done);
|
||||||
|
|
||||||
|
var WebSocket = Server.websocketConstructor();
|
||||||
|
var ws_url = protocol+'://localhost:'+port_conf.port + '/';
|
||||||
|
var ws = new WebSocket(ws_url);
|
||||||
|
|
||||||
|
ws.onopen = function () {
|
||||||
|
assert(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (protocol == 'wss') {
|
||||||
|
setTimeout(function () {
|
||||||
|
assert.equal(ws.readyState, 0);
|
||||||
|
done_once();
|
||||||
|
}, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.onerror = ws.onclose = function (m) {
|
||||||
|
assert(true);
|
||||||
|
done_once();
|
||||||
|
};
|
||||||
|
} else if (type == 'ht') {
|
||||||
|
var url = protocol+'://localhost:'+port_conf.port + '/';
|
||||||
|
|
||||||
|
var post_options = {
|
||||||
|
url: url,
|
||||||
|
json: true,
|
||||||
|
body: {
|
||||||
|
method: 'server_info',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
request.post(post_options, function (err, response, body) {
|
||||||
|
assert(!body);
|
||||||
|
assert(!response);
|
||||||
|
assert(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error('unknown protocol: ' + protocol);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
suite("Uniport tests", function () {
|
||||||
|
var $ = { };
|
||||||
|
|
||||||
|
suiteSetup(function (done) {
|
||||||
|
testutils.build_setup({}, 'uniport_tests').call($, function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
suiteTeardown(function (done) {
|
||||||
|
testutils.build_teardown('uniport_tests').call($, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('connection', function () {
|
||||||
|
var define_test = mark_redundant_tests();
|
||||||
|
|
||||||
|
for_each_item(config.uniport_test_ports, function (name, conf) {
|
||||||
|
var protocols = client_protocols(conf);
|
||||||
|
|
||||||
|
define_suite(name, function () {
|
||||||
|
['http', 'https', 'ws', 'wss'].forEach(function (p) {
|
||||||
|
var op = same_protocol_opposite_security(p);
|
||||||
|
if (!(~protocols.indexOf(p)) &&
|
||||||
|
~(protocols.indexOf(op))) {
|
||||||
|
|
||||||
|
var test_name = "can't connect using " + p +
|
||||||
|
" with only " + op + " set";
|
||||||
|
|
||||||
|
define_test( test_name,
|
||||||
|
function (done){
|
||||||
|
test_cant_connect(conf, p, done);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('admin commands', function () {
|
||||||
|
var define_test = mark_redundant_tests(function (test_name) {
|
||||||
|
// The password checking should be the same regardless of protocol,
|
||||||
|
// so we normalize the test name (used to determine test redundancy).
|
||||||
|
return test_name.replace('wss', 'ws')
|
||||||
|
.replace('https', 'http');
|
||||||
|
});
|
||||||
|
|
||||||
|
for_each_item(config.uniport_test_ports, function (name, conf) {
|
||||||
|
define_suite(name, function () {
|
||||||
|
var protocols = client_protocols(conf);
|
||||||
|
|
||||||
|
var allow_admin = conf.admin == 'allow';
|
||||||
|
var require_pass = Boolean(conf.admin_password);
|
||||||
|
|
||||||
|
function test_for (protocol, params) {
|
||||||
|
return function (done) {
|
||||||
|
test_admin_command(params, protocol, conf, done);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
if (allow_admin && require_pass) {
|
||||||
|
protocols.forEach(function (protocol) {
|
||||||
|
var can_not_issue_admin_commands =
|
||||||
|
'can not issue admin commands on '+ protocol + ' ';
|
||||||
|
|
||||||
|
define_test(
|
||||||
|
('can issue admin commands on '+protocol+
|
||||||
|
' with correct credentials'),
|
||||||
|
test_for(protocol,
|
||||||
|
{expect_success: true, send_credentials: true})
|
||||||
|
);
|
||||||
|
define_test(
|
||||||
|
can_not_issue_admin_commands + 'with wrong password',
|
||||||
|
test_for(protocol, {expect_success: false,
|
||||||
|
send_credentials: true,
|
||||||
|
wrong_pass: true})
|
||||||
|
);
|
||||||
|
define_test(
|
||||||
|
can_not_issue_admin_commands + 'with garbage password',
|
||||||
|
test_for(protocol, {expect_success: false,
|
||||||
|
send_credentials: true,
|
||||||
|
wrong_pass: 'send_object_instead_of_string'})
|
||||||
|
);
|
||||||
|
define_test(
|
||||||
|
can_not_issue_admin_commands + ' with wrong user',
|
||||||
|
test_for(protocol, {expect_success: false,
|
||||||
|
send_credentials: true,
|
||||||
|
wrong_user: true})
|
||||||
|
);
|
||||||
|
define_test(
|
||||||
|
can_not_issue_admin_commands + 'without credentials',
|
||||||
|
test_for(protocol, {expect_success: false,
|
||||||
|
send_credentials: false})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (allow_admin)
|
||||||
|
{
|
||||||
|
protocols.forEach(function (protocol) {
|
||||||
|
define_test(
|
||||||
|
'can issue admin commands on ' + protocol,
|
||||||
|
test_for(protocol, {expect_success: true,
|
||||||
|
send_credentials: false})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (!allow_admin)
|
||||||
|
{
|
||||||
|
protocols.forEach(function (protocol) {
|
||||||
|
define_test(
|
||||||
|
'can not issue admin commands on ' + protocol,
|
||||||
|
test_for(protocol, {expect_success: false,
|
||||||
|
send_credentials: false})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user