diff --git a/receiver/CMakeLists.txt b/receiver/CMakeLists.txt index c0c8366e39a83c975767e9ebf9818a6f160f27ae..78163ae777338f3c8639ff7980d0eb0c04278a7b 100644 --- a/receiver/CMakeLists.txt +++ b/receiver/CMakeLists.txt @@ -16,6 +16,7 @@ set(RECEIVER_CORE_FILES src/request_handler/request_handler_db_write.cpp src/request_handler/request_handler_receive_data.cpp src/request_handler/request_handler_authorize.cpp + src/request_handler/authorization_client.cpp src/request_handler/request_handler_db_meta_write.cpp src/request_handler/request_handler_db_stream_info.cpp src/request_handler/request_handler_db_last_stream.cpp diff --git a/receiver/src/request_handler/authorization_client.cpp b/receiver/src/request_handler/authorization_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f81f8dfceba7dbdb9b303844f58e06e14688dc19 --- /dev/null +++ b/receiver/src/request_handler/authorization_client.cpp @@ -0,0 +1,93 @@ +#include "authorization_client.h" + +#include "asapo/json_parser/json_parser.h" + + +#include "../receiver_config.h" +#include "../receiver_logger.h" +#include "../request.h" + + +namespace asapo { + +std::string AuthorizationClient::GetRequestString(const Request* request, const std::string& source_credentials) const { + std::string request_string = std::string("{\"SourceCredentials\":\"") + + source_credentials + "\",\"OriginHost\":\"" + request->GetOriginUri() + "\"}"; + return request_string; +} + +Error AuthorizationClient::ErrorFromAuthorizationServerResponse(const Error& err, const std::string response, + HttpCode code) const { + if (err) { + return asapo::ReceiverErrorTemplates::kInternalServerError.Generate( + "cannot authorize request: " + err->Explain()); + } else { + if (code != HttpCode::Unauthorized) { + return asapo::ReceiverErrorTemplates::kInternalServerError.Generate( + response + " return code " + std::to_string(int( + code))); + } + return asapo::ReceiverErrorTemplates::kAuthorizationFailure.Generate(response); + } +} + +Error CheckAccessType(SourceType source_type, const std::vector<std::string>& access_types) { + if (std::find(access_types.begin(), access_types.end(), + source_type == SourceType::kProcessed ? "write" : "writeraw") != access_types.end()) { + return nullptr; + } else { + return asapo::ReceiverErrorTemplates::kAuthorizationFailure.Generate("wrong access types"); + } +} + +LogMessageWithFields AuthErrorLogMsg(const Request* request, const Error& err, const std::string& request_string) { + return RequestLog("failure authorizing: " + err->Explain(), request) + .Append("authServer", GetReceiverConfig()->authorization_server) + .Append("request", request_string); +} + +Error AuthorizationClient::Authorize(const Request* request, std::string source_credentials, AuthorizationData* data) const { + HttpCode code; + Error err; + std::string request_string = GetRequestString(request, std::move(source_credentials)); + auto response = + http_client__->Post(GetReceiverConfig()->authorization_server + "/authorize", "", request_string, &code, + &err); + if (err || code != HttpCode::OK) { + auto auth_error = ErrorFromAuthorizationServerResponse(err, response, code); + log__->Error(AuthErrorLogMsg(request, auth_error, request_string)); + return auth_error; + } + + std::string stype; + std::vector<std::string> access_types; + + AuthorizationData creds; + JsonStringParser parser{response}; + (err = parser.GetString("beamtimeId", &creds.beamtime_id)) || + (err = parser.GetString("dataSource", &creds.data_source)) || + (err = parser.GetString("corePath", &creds.offline_path)) || + (err = parser.GetString("beamline-path", &creds.online_path)) || + (err = parser.GetString("source-type", &stype)) || + (err = parser.GetArrayString("access-types", &access_types)) || + (err = GetSourceTypeFromString(stype, &creds.source_type)) || + (err = parser.GetString("beamline", &creds.beamline)); + if (err) { + return ErrorFromAuthorizationServerResponse(err, "", code); + } + + err = CheckAccessType(creds.source_type, access_types); + if (err) { + log__->Error(AuthErrorLogMsg(request, err, request_string)); + return err; + } + log__->Debug(RequestLog("authorized connection",request)); + *data = creds; + return nullptr; +} + +AuthorizationClient::AuthorizationClient() : log__{GetDefaultReceiverLogger()}, + http_client__{DefaultHttpClient()} { +} + +} diff --git a/receiver/src/request_handler/authorization_client.h b/receiver/src/request_handler/authorization_client.h new file mode 100644 index 0000000000000000000000000000000000000000..5734ada051fb459727ca8ccec2a65557addfa172 --- /dev/null +++ b/receiver/src/request_handler/authorization_client.h @@ -0,0 +1,35 @@ +#ifndef ASAPO_RECEIVER_SRC_REQUEST_HANDLER_AUTHORIZATION_CLIENT_H_ +#define ASAPO_RECEIVER_SRC_REQUEST_HANDLER_AUTHORIZATION_CLIENT_H_ + +#include "asapo/io/io.h" +#include "asapo/http_client/http_client.h" + +namespace asapo { + +struct AuthorizationData { + std::string beamtime_id; + std::string data_source; + std::string beamline; + std::string offline_path; + std::string online_path; + SourceType source_type; +}; + +class Request; +class AbstractLogger; + +class AuthorizationClient { + public: + AuthorizationClient(); + Error Authorize(const Request* request, std::string source_credentials, AuthorizationData* data) const; + const AbstractLogger* log__; + std::unique_ptr<HttpClient>http_client__; + private: + Error ErrorFromAuthorizationServerResponse(const Error& err, const std::string response, HttpCode code) const; + void SetRequestFields(Request* request) const; + std::string GetRequestString(const Request* request, const std::string& source_credentials) const; +}; + +} + +#endif //ASAPO_RECEIVER_SRC_REQUEST_HANDLER_AUTHORIZATION_CLIENT_H_ diff --git a/receiver/src/request_handler/request_handler_authorize.cpp b/receiver/src/request_handler/request_handler_authorize.cpp index 0230988c1920527393d390d486fff1423d668ecf..67f2ab3f251090cafe6ab43b5e185ce06aa7f855 100644 --- a/receiver/src/request_handler/request_handler_authorize.cpp +++ b/receiver/src/request_handler/request_handler_authorize.cpp @@ -10,90 +10,12 @@ using std::chrono::system_clock; namespace asapo { -std::string RequestHandlerAuthorize::GetRequestString(const Request* request, const char* source_credentials) const { - std::string request_string = std::string("{\"SourceCredentials\":\"") + - source_credentials + "\",\"OriginHost\":\"" + request->GetOriginUri() + "\"}"; - return request_string; -} - -Error RequestHandlerAuthorize::ErrorFromAuthorizationServerResponse(const Error& err, const std::string response, - HttpCode code) const { - if (err) { - return asapo::ReceiverErrorTemplates::kInternalServerError.Generate("cannot authorize request: " + err->Explain()); - } else { - if (code != HttpCode::Unauthorized) { - return asapo::ReceiverErrorTemplates::kInternalServerError.Generate(response + " return code " + std::to_string(int( - code))); - } - return asapo::ReceiverErrorTemplates::kAuthorizationFailure.Generate(response); - } -} - -Error CheckAccessType(SourceType source_type, const std::vector<std::string>& access_types) { - if(std::find(access_types.begin(), access_types.end(), - source_type == SourceType::kProcessed ? "write" : "writeraw") != access_types.end()) { - return nullptr; - } else { - return asapo::ReceiverErrorTemplates::kAuthorizationFailure.Generate("wrong access types"); - } -} - - -Error RequestHandlerAuthorize::Authorize(Request* request, const char* source_credentials) const { - HttpCode code; - Error err; - std::string request_string = GetRequestString(request, source_credentials); - auto response = http_client__->Post(GetReceiverConfig()->authorization_server + "/authorize", "", request_string, &code, - &err); - if (err || code != HttpCode::OK) { - auto auth_error = ErrorFromAuthorizationServerResponse(err, response, code); - log__->Error("failure authorizing at " + GetReceiverConfig()->authorization_server + " request: " + request_string + - " - " + - auth_error->Explain()); - return auth_error; - } - - std::string stype; - std::vector<std::string> access_types; - - JsonStringParser parser{response}; - (err = parser.GetString("beamtimeId", &beamtime_id_)) || - (err = parser.GetString("dataSource", &data_source_)) || - (err = parser.GetString("corePath", &offline_path_)) || - (err = parser.GetString("beamline-path", &online_path_)) || - (err = parser.GetString("source-type", &stype)) || - (err = parser.GetArrayString("access-types", &access_types)) || - (err = GetSourceTypeFromString(stype, &source_type_)) || - (err = parser.GetString("beamline", &beamline_)); - if (err) { - return ErrorFromAuthorizationServerResponse(err, "", code); - } - - err = CheckAccessType(source_type_, access_types); - if (err) { - log__->Error("failure authorizing at " + GetReceiverConfig()->authorization_server + " request: " + request_string + - " - " + - err->Explain()); - return err; - } - - log__->Debug(std::string("authorized connection from ") + request->GetOriginUri() + "source type: " + stype + - " beamline: " + - beamline_ + ", beamtime id: " + beamtime_id_ + ", data soucre: " + data_source_); - - last_updated_ = system_clock::now(); - cached_source_credentials_ = source_credentials; - - return nullptr; -} - Error RequestHandlerAuthorize::CheckVersion(const std::string& version_from_client) const { int verClient = VersionToNumber(version_from_client); int verService = VersionToNumber(GetReceiverApiVersion()); if (verClient > verService) { auto err_string = "client version: " + version_from_client + ", server version: " + GetReceiverApiVersion(); return asapo::ReceiverErrorTemplates::kUnsupportedClient.Generate(err_string); - log__->Error("failure serving client - unsupported version, " + err_string); } return nullptr; } @@ -102,27 +24,33 @@ Error RequestHandlerAuthorize::ProcessAuthorizationRequest(Request* request) con if (!cached_source_credentials_.empty()) { Error auth_error = asapo::ReceiverErrorTemplates::kAuthorizationFailure.Generate(); auth_error->Append("already authorized"); - log__->Error("failure authorizing at " + GetReceiverConfig()->authorization_server + " - " + - "already authorized"); return auth_error; } auto err = CheckVersion(request->GetApiVersion()); if (err) { - log__->Error("failure authorizing at client: " + err->Explain()); + return err; + } + err = auth_client__->Authorize(request, request->GetMetaData().c_str(),&cached_auth_); + if (err) { return err; } - return Authorize(request, request->GetMetaData().c_str()); + cached_source_credentials_ = request->GetMetaData(); + last_updated_ = system_clock::now(); + return nullptr; } Error RequestHandlerAuthorize::ProcessReAuthorization(Request* request) const { - std::string old_beamtimeId = beamtime_id_; - auto err = Authorize(request, cached_source_credentials_.c_str()); + std::string old_beamtimeId = cached_auth_.beamtime_id; + auto err = auth_client__->Authorize(request, cached_source_credentials_.c_str(),&cached_auth_); if (err == asapo::ReceiverErrorTemplates::kAuthorizationFailure || ( - err == nullptr && old_beamtimeId != beamtime_id_)) { + err == nullptr && old_beamtimeId != cached_auth_.beamtime_id)) { return asapo::ReceiverErrorTemplates::kReAuthorizationFailure.Generate(); } + if (err==nullptr) { + last_updated_ = system_clock::now(); + } return err; } @@ -132,6 +60,15 @@ bool RequestHandlerAuthorize::NeedReauthorize() const { return elapsed_ms >= GetReceiverConfig()->authorization_interval_ms; } +void RequestHandlerAuthorize::SetRequestFields(Request* request) const { + request->SetBeamtimeId(cached_auth_.beamtime_id); + request->SetBeamline(cached_auth_.beamline); + request->SetDataSource(cached_auth_.data_source); + request->SetOfflinePath(cached_auth_.offline_path); + request->SetOnlinePath(cached_auth_.online_path); + request->SetSourceType(cached_auth_.source_type); +} + Error RequestHandlerAuthorize::ProcessOtherRequest(Request* request) const { if (cached_source_credentials_.empty()) { @@ -144,16 +81,10 @@ Error RequestHandlerAuthorize::ProcessOtherRequest(Request* request) const { return err; } } - request->SetBeamtimeId(beamtime_id_); - request->SetBeamline(beamline_); - request->SetDataSource(data_source_); - request->SetOfflinePath(offline_path_); - request->SetOnlinePath(online_path_); - request->SetSourceType(source_type_); + SetRequestFields(request); return nullptr; } - Error RequestHandlerAuthorize::ProcessRequest(Request* request) const { if (request->GetOpCode() == kOpcodeAuthorize) { return ProcessAuthorizationRequest(request); @@ -162,8 +93,8 @@ Error RequestHandlerAuthorize::ProcessRequest(Request* request) const { } } -RequestHandlerAuthorize::RequestHandlerAuthorize(): log__{GetDefaultReceiverLogger()}, - http_client__{DefaultHttpClient()} { +RequestHandlerAuthorize::RequestHandlerAuthorize() : log__{GetDefaultReceiverLogger()}, + auth_client__{new AuthorizationClient()} { } StatisticEntity RequestHandlerAuthorize::GetStatisticEntity() const { diff --git a/receiver/src/request_handler/request_handler_authorize.h b/receiver/src/request_handler/request_handler_authorize.h index adbb7b5af739d0f568791bad68139fdbaa3d2e8f..d091b385a0ab4af77601eaa7054dfc50e5562962 100644 --- a/receiver/src/request_handler/request_handler_authorize.h +++ b/receiver/src/request_handler/request_handler_authorize.h @@ -6,6 +6,7 @@ #include "request_handler.h" #include "asapo/logger/logger.h" #include "asapo/http_client/http_client.h" +#include "authorization_client.h" #include "asapo/io/io.h" @@ -18,25 +19,17 @@ class RequestHandlerAuthorize final: public ReceiverRequestHandler { StatisticEntity GetStatisticEntity() const override; Error ProcessRequest(Request* request) const override; const AbstractLogger* log__; - std::unique_ptr<HttpClient>http_client__; + std::unique_ptr<AuthorizationClient> auth_client__; private: - mutable std::string beamtime_id_; - mutable std::string data_source_; - mutable std::string beamline_; - mutable std::string offline_path_; - mutable std::string online_path_; - mutable SourceType source_type_; + mutable AuthorizationData cached_auth_; mutable std::string cached_source_credentials_; mutable std::chrono::system_clock::time_point last_updated_; Error ProcessAuthorizationRequest(Request* request) const; Error ProcessOtherRequest(Request* request) const; - Error Authorize(Request* request, const char* source_credentials) const; - Error ErrorFromAuthorizationServerResponse(const Error& err, const std::string response, HttpCode code) const; Error ProcessReAuthorization(Request* request) const; bool NeedReauthorize() const; - std::string GetRequestString(const Request* request, const char* source_credentials) const; + void SetRequestFields(Request* request) const; Error CheckVersion(const std::string& version_from_client) const; - }; } diff --git a/receiver/unittests/request_handler/test_request_handler_authorizer.cpp b/receiver/unittests/request_handler/test_request_handler_authorizer.cpp index 30069b6e2531890a4a8ac168f0ab092ea964e620..418de43741e23694a6bf7ed7d47e5d966e48f6f7 100644 --- a/receiver/unittests/request_handler/test_request_handler_authorizer.cpp +++ b/receiver/unittests/request_handler/test_request_handler_authorizer.cpp @@ -50,7 +50,7 @@ namespace { TEST(Authorizer, Constructor) { RequestHandlerAuthorize handler; - ASSERT_THAT(dynamic_cast<asapo::HttpClient*>(handler.http_client__.get()), Ne(nullptr)); +// ASSERT_THAT(dynamic_cast<asapo::HttpClient*>(handler.http_client__.get()), Ne(nullptr)); ASSERT_THAT(dynamic_cast<const asapo::AbstractLogger*>(handler.log__), Ne(nullptr)); } @@ -131,20 +131,26 @@ class AuthorizerHandlerTests : public Test { } else if (!opError) { EXPECT_CALL(mock_logger, Debug(AllOf(HasSubstr("authorized"), HasSubstr(expected_beamtime_id), - HasSubstr(expected_beamline), - HasSubstr(expected_source_type_str), +// HasSubstr(expected_beamline), +// HasSubstr(expected_source_type_str), HasSubstr(expected_data_source), HasSubstr(expected_producer_uri)))); - } else { - EXPECT_CALL(mock_logger, Error(HasSubstr("wrong"))); } } - - } Error MockFirstAuthorization(bool error, HttpCode code = HttpCode::OK, bool opError = false) { + + if (!error && code == HttpCode::OK && !opError) { + EXPECT_CALL(*mock_request, SetBeamtimeId(expected_beamtime_id)); + EXPECT_CALL(*mock_request, SetDataSource(expected_data_source)); + EXPECT_CALL(*mock_request, SetOfflinePath(expected_core_path)); + EXPECT_CALL(*mock_request, SetOnlinePath(expected_beamline_path)); + EXPECT_CALL(*mock_request, SetBeamline(expected_beamline)); + EXPECT_CALL(*mock_request, SetSourceType(expected_source_type)); + } + EXPECT_CALL(*mock_request, GetOpCode()) - .WillOnce(Return(asapo::kOpcodeAuthorize)) + .WillRepeatedly(Return(asapo::kOpcodeAuthorize)) ; EXPECT_CALL(*mock_request, GetMetaData()) .WillOnce(ReturnRef(expected_source_credentials)) @@ -154,13 +160,24 @@ class AuthorizerHandlerTests : public Test { .WillOnce(Return(expected_api_version)) ; + EXPECT_CALL(*mock_request, GetDataSource()) + .WillRepeatedly(ReturnRef(expected_data_source)) + ; + + EXPECT_CALL(*mock_request, GetStream()) + .WillRepeatedly(Return("stream")) + ; + + EXPECT_CALL(*mock_request, GetBeamtimeId()) + .WillRepeatedly(ReturnRef(expected_beamtime_id)) + ; MockAuthRequest(error, code, opError); return handler.ProcessRequest(mock_request.get()); } Error MockRequestAuthorization(bool error, HttpCode code = HttpCode::OK, bool set_request = true) { EXPECT_CALL(*mock_request, GetOpCode()) - .WillOnce(Return(asapo::kOpcodeTransferData)) + .WillRepeatedly(Return(asapo::kOpcodeTransferData)) ; if (!error && code == HttpCode::OK && set_request) { @@ -240,6 +257,7 @@ TEST_F(AuthorizerHandlerTests, AuthorizeFailsOnWrongAccessTypeForProcessed) { TEST_F(AuthorizerHandlerTests, AuthorizeOkForRaw) { expected_access_type_str = "[\"writeraw\"]"; expected_source_type_str = "raw"; + expected_source_type = asapo::SourceType::kRaw; auto err = MockFirstAuthorization(false, HttpCode::OK, false); ASSERT_THAT(err, Eq(nullptr)); } @@ -249,11 +267,6 @@ TEST_F(AuthorizerHandlerTests, ErrorOnSecondAuthorize) { EXPECT_CALL(*mock_request, GetOpCode()) .WillOnce(Return(asapo::kOpcodeAuthorize)); - EXPECT_CALL(mock_logger, Error(AllOf(HasSubstr("failure authorizing"), - HasSubstr("already authorized"), - HasSubstr(expected_authorization_server)))); - - auto err = handler.ProcessRequest(mock_request.get()); ASSERT_THAT(err, Eq(asapo::ReceiverErrorTemplates::kAuthorizationFailure)); @@ -285,10 +298,9 @@ TEST_F(AuthorizerHandlerTests, DataTransferRequestAuthorizeReturnsSameBeamtimeId TEST_F(AuthorizerHandlerTests, RequestAuthorizeReturnsDifferentBeamtimeId) { MockFirstAuthorization(false); - expected_beamtime_id = "different_id"; - auto err = MockRequestAuthorization(false, HttpCode::OK, false); + auto err = MockRequestAuthorization(false, HttpCode::OK, false); ASSERT_THAT(err, Eq(asapo::ReceiverErrorTemplates::kReAuthorizationFailure)); } @@ -305,9 +317,6 @@ TEST_F(AuthorizerHandlerTests, RequestFromUnsupportedClient) { ASSERT_THAT(err, Eq(asapo::ReceiverErrorTemplates::kUnsupportedClient)); } - - - TEST_F(AuthorizerHandlerTests, DataTransferRequestAuthorizeUsesCachedValue) { config.authorization_interval_ms = 10000; SetReceiverConfig(config, "none");