Skip to content

Commit cc46332

Browse files
committed
Add an authentication token to all client-server communication.
1 parent 5a66c2b commit cc46332

File tree

5 files changed

+39
-4
lines changed

5 files changed

+39
-4
lines changed

JUPYTER.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,12 @@ kernel::
102102
${HOME}/miniconda3/bin/jupyter notebook
103103

104104
There is a sample `schwarzschild.ipynb` in the `examples` directory.
105+
106+
107+
Setting up a Jupyterhub server for Cadabra
108+
------------------------------------------
109+
110+
First install miniconda as per the instructions above. Then do::
111+
112+
conda install jupyterhub
113+

client_server/ComputeThread.cc

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ void ComputeThread::try_spawn_server()
205205
throw std::logic_error("Failed to read port from server.");
206206
}
207207
port = atoi(buffer);
208+
if(fscanf(f, "%100s", buffer)!=1) {
209+
throw std::logic_error("Failed to read authentication token from server.");
210+
}
211+
authentication_token=std::string(buffer);
212+
// std::cerr << "auth token: " << authentication_token << std::endl;
208213
}
209214
catch(Glib::SpawnError& err) {
210215
std::cerr << "Failed to start server " << argv[0] << ": " << err.what() << std::endl;
@@ -424,8 +429,9 @@ void ComputeThread::execute_interactive(const std::string& code)
424429
header["interactive"] = true;
425430
content["code"] = code.c_str();
426431

427-
req["header"] = header;
428-
req["content"] = content;
432+
req["auth_token"] = authentication_token;
433+
req["header"] = header;
434+
req["content"] = content;
429435

430436
std::ostringstream oss;
431437
oss << req << std::endl;
@@ -484,6 +490,7 @@ void ComputeThread::execute_cell(DTree::iterator it)
484490
else
485491
header["cell_origin"]="server";
486492
header["msg_type"]="execute_request";
493+
req["auth_token"]=authentication_token;
487494
req["header"]=header;
488495
content["code"]=dc.textbuf;
489496
req["content"]=content;
@@ -522,6 +529,7 @@ void ComputeThread::stop()
522529
Json::Value req, header, content;
523530
header["uuid"]="none";
524531
header["msg_type"]="execute_interrupt";
532+
req["auth_token"]=authentication_token;
525533
req["header"]=header;
526534

527535
std::ostringstream str;
@@ -550,6 +558,7 @@ void ComputeThread::restart_kernel()
550558
header["uuid"]="none";
551559
header["msg_type"]="exit";
552560
header["from_server"] = true;
561+
req["auth_token"]=authentication_token;
553562
req["header"]=header;
554563

555564
std::ostringstream str;

client_server/ComputeThread.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ namespace cadabra {
132132
Glib::Pid server_pid;
133133
int server_stdout, server_stderr;
134134
unsigned short port;
135+
std::string authentication_token;
135136
int forced_server_port;
136137
};
137138

client_server/Server.cc

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ Server::Server()
3131
: return_cell_id(std::numeric_limits<uint64_t>::max()/2)
3232
{
3333
// FIXME: we do not actually do anything with this.
34+
auto gen = boost::uuids::random_generator();
35+
auto authentication_uuid = gen();
36+
authentication_token = boost::uuids::to_string( authentication_uuid );
3437
socket_name="tcp://localhost:5454";
3538
init();
3639
}
@@ -359,8 +362,15 @@ void Server::dispatch_message(websocketpp::connection_hdl hdl, const std::string
359362
return;
360363
}
361364

362-
const Json::Value content = root["content"];
363-
const Json::Value header = root["header"];
365+
// Check that this message is authenticated.
366+
std::string auth_token = root["auth_token"].asString();
367+
if(auth_token!=authentication_token) {
368+
std::cerr << "Received block with incorrect authentication token: " << auth_token << "." << std::endl;
369+
return;
370+
}
371+
372+
const Json::Value content = root["content"];
373+
const Json::Value header = root["header"];
364374
std::string msg_type = header["msg_type"].asString();
365375
// std::cerr << "received msg_type |" << msg_type << "|" << std::endl;
366376

@@ -521,6 +531,7 @@ void Server::run()
521531
websocketpp::lib::asio::error_code ec;
522532
auto p = wserver.get_local_endpoint(ec);
523533
std::cout << p.port() << std::endl;
534+
std::cout << authentication_token << std::endl;
524535

525536
// std::cerr << "cadabra-server: spawning job thread " << std::endl;
526537
runner = std::thread(std::bind(&Server::wait_for_job, this));

client_server/Server.hh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class Server {
110110
// the server, but they all have access to the same Python
111111
// scope. With multiple connections, one can inspect the Python
112112
// stack from a different client (e.g. for debugging purposes).
113+
// All connections share the same authentication token.
113114

114115
class Connection {
115116
public:
@@ -122,6 +123,10 @@ class Server {
122123
std::owner_less<websocketpp::connection_hdl>> ConnectionMap;
123124
ConnectionMap connections;
124125

126+
// Authentication token, needs to be sent along with any message.
127+
// Gets set when the server announces its port.
128+
std::string authentication_token;
129+
125130
// Mutex to be able to use the websocket layer from both the
126131
// main loop and the python-running thread.
127132
std::mutex ws_mutex;

0 commit comments

Comments
 (0)