Commit 79adb9c1 authored by Michael Ott's avatar Michael Ott
Browse files

Add authentication via HTTP POST and cookies

parent aa9c7a04
......@@ -122,6 +122,6 @@ libdcdbplugin_caliper.$(LIBEXT): sensors/caliper/CaliperSensorGroup.o sensors/ca
$(NVCC) -shared --compiler-options '-fPIC' -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lboost_log -lboost_system -lnvidia-ml
libdcdbplugin_rest.$(LIBEXT): sensors/rest/RESTSensorGroup.o sensors/rest/RESTUnit.o sensors/rest/RESTConfigurator.o
$(CXX) $(LIBFLAGS)$@ -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lcrypto -lssl -lboost_log -lboost_system
$(CXX) $(LIBFLAGS)$@ -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lcrypto -lssl -lboost_regex -lboost_log -lboost_system
......@@ -54,5 +54,7 @@ void RESTConfigurator::sensorGroup(RESTSensorGroup &s, CFG_VAL config) {
void RESTConfigurator::sensorEntity(RESTUnit &s, CFG_VAL config) {
ADD {
ATTRIBUTE("baseurl", setBaseURL);
ATTRIBUTE("authendpoint", setAuthEndpoint);
ATTRIBUTE("authdata", setAuthData);
}
}
......@@ -42,6 +42,12 @@ RESTUnit::RESTUnit(const std::string &name)
RESTUnit::RESTUnit(const RESTUnit &other)
: EntityInterface(other),
_ctx(ssl::context::tlsv12_client),
_baseURL(other._baseURL),
_hostname(other._hostname),
_port(other._port),
_path(other._path),
_authEndpoint(other._authEndpoint),
_authData(other._authData),
_ssl(false) {
}
......@@ -50,6 +56,12 @@ RESTUnit::~RESTUnit() {
RESTUnit &RESTUnit::operator=(const RESTUnit &other) {
EntityInterface::operator=(other);
_baseURL = other._baseURL;
_hostname = other._hostname;
_port = other._port;
_path = other._path;
_authEndpoint = other._authEndpoint;
_authData = other._authData;
_ssl = other._ssl;
return *this;
......@@ -58,30 +70,78 @@ RESTUnit &RESTUnit::operator=(const RESTUnit &other) {
void RESTUnit::execOnInit() {
}
bool RESTUnit::authenticate() {
tcp::resolver resolver(_ioc);
auto const hosts = resolver.resolve(_hostname, _port);
beast::ssl_stream<beast::tcp_stream> stream(_ioc, _ctx);
beast::get_lowest_layer(stream).connect(hosts);
if (_ssl) {
if(! SSL_set_tlsext_host_name(stream.native_handle(), _hostname.c_str()))
{
beast::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()};
throw beast::system_error{ec};
}
stream.handshake(ssl::stream_base::client);
}
http::request<http::string_body> auth{http::verb::post, _path + _authEndpoint, 11};
auth.set(http::field::host, _hostname);
auth.body() = _authData;
auth.prepare_payload();
if (_ssl) {
http::write(stream, auth);
} else {
http::write(beast::get_lowest_layer(stream), auth);
}
beast::flat_buffer buffer;
http::response<http::string_body> res;
if (_ssl) {
http::read(stream, buffer, res);
} else {
http::read(beast::get_lowest_layer(stream), buffer, res);
}
_cookie = std::string(res[http::field::set_cookie]);
if (_cookie.size() > 0) {
LOG(debug) << "Authenticated to " << _hostname << ", received cookie: " << _cookie;
return true;
} else {
LOG(info) << "Could not authenticate to " << _hostname << ", no cookie received.";
return false;
}
}
bool RESTUnit::sendRequest(const std::string &endpoint, const std::string &request, std::string &response) {
// Look up the domain name
if ((_authData.size() > 0) && (_cookie.size() == 0) && (!authenticate())) {
return false;
}
tcp::resolver resolver(_ioc);
auto const hosts = resolver.resolve(_hostname, _port);
beast::ssl_stream<beast::tcp_stream> stream(_ioc, _ctx);
// Make the connection on the IP address we get from a lookup
beast::get_lowest_layer(stream).connect(hosts);
if (_ssl) {
// Set SNI Hostname (many hosts need this to handshake successfully)
if(! SSL_set_tlsext_host_name(stream.native_handle(), _hostname.c_str()))
{
beast::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()};
throw beast::system_error{ec};
}
// Perform the SSL handshake
stream.handshake(ssl::stream_base::client);
}
// Set up an HTTP GET request message
http::request<http::string_body> req{http::verb::get, _path + endpoint, 11};
req.set(http::field::host, _hostname);
if (_cookie.size() > 0) {
req.set(http::field::cookie, _cookie);
}
req.body() = request;
req.prepare_payload();
......
......@@ -94,8 +94,13 @@ class RESTUnit : public EntityInterface {
}
}
}
const std::string &getBaseURL() { return _baseURL; }
void setAuthEndpoint(const std::string &authEndpoint) { _authEndpoint = authEndpoint; }
void setAuthData(const std::string &authData) { _authData = authData; }
const std::string &getBaseURL() { return _baseURL; }
const std::string &getAuthEndpoint() { return _authEndpoint; }
const std::string &getAuthData() { return _authData; }
bool authenticate();
/**
* Send the request to the host and write the response into response.
*
......@@ -115,6 +120,9 @@ class RESTUnit : public EntityInterface {
std::string _hostname;
std::string _port;
std::string _path;
std::string _authEndpoint;
std::string _authData;
std::string _cookie;
bool _ssl;
};
......
Markdown is supported
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