Skip to content

Commit

Permalink
Build out /authorized API call
Browse files Browse the repository at this point in the history
- Add HttpParams for query parameter passing
- Add echo endpoint to mock server to test parameter handling
- Update ApiClient test to use new HTTP interface
- Use slightly more real data for "authorized?" call
- Update ApiClient.isAllowed implementation to use req values as
  parameters (that is, use the new API call)
  • Loading branch information
botimer committed Nov 13, 2023
1 parent e03ce2b commit 60ea186
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 20 deletions.
3 changes: 3 additions & 0 deletions apache/client/include/lauth/http_client.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef __LAUTH_HTTP_CLIENT_HPP__
#define __LAUTH_HTTP_CLIENT_HPP__

#include "lauth/http_params.hpp"

#include <optional>
#include <string>

Expand All @@ -11,6 +13,7 @@ namespace mlibrary::lauth {
virtual ~HttpClient() = default;

virtual std::optional<std::string> get(const std::string &path);
virtual std::optional<std::string> get(const std::string &path, const HttpParams &params);

protected:
const std::string baseUrl;
Expand Down
13 changes: 13 additions & 0 deletions apache/client/include/lauth/http_params.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef __LAUTH_HTTP_PARAMS_HPP__
#define __LAUTH_HTTP_PARAMS_HPP__

#include <httplib.h>

#include <map>
#include <string>

namespace mlibrary::lauth {
using HttpParams = std::multimap<std::string, std::string>;
}

#endif // __LAUTH_HTTP_PARAMS_HPP__
2 changes: 2 additions & 0 deletions apache/client/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ install_headers(
'include/lauth/api_client.hpp',
'include/lauth/authorizer.hpp',
'include/lauth/http_client.hpp',
'include/lauth/http_params.hpp',
'include/lauth/request.hpp',
subdir: 'lauth')

Expand Down Expand Up @@ -88,6 +89,7 @@ executable(
files(['test/mock_service.cpp']),
dependencies: [
cpp_httplib,
json,
],
link_args: httplib_links
)
Expand Down
9 changes: 6 additions & 3 deletions apache/client/src/lauth/api_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@

namespace mlibrary::lauth {
bool ApiClient::isAllowed(Request req) {
std::stringstream url;
url << "/users/" << req.user << "/is_allowed";
auto result = client->get(url.str());
HttpParams params {
{"uri", req.uri},
{"user", req.user}
};

auto result = client->get("/authorized", params);
return result == "yes";
}
}
16 changes: 14 additions & 2 deletions apache/client/src/lauth/http_client.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#include "lauth/http_client.hpp"

#include <optional>

#include <httplib.h>

#include <optional>
#include "lauth/http_params.hpp"

namespace mlibrary::lauth {
std::optional<std::string> HttpClient::get(const std::string& path) {
Expand All @@ -14,5 +16,15 @@ namespace mlibrary::lauth {
else
return std::nullopt;
}
}

std::optional<std::string> HttpClient::get(const std::string& path, const HttpParams& params) {
httplib::Client client(baseUrl);
httplib::Headers headers;

auto res = client.Get(path, params, headers);
if (res)
return res->body;
else
return std::nullopt;
}
}
36 changes: 23 additions & 13 deletions apache/client/test/lauth/api_client_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,41 @@ using namespace mlibrary::lauth;

TEST(ApiClient, RequestByAuthorizedUserIsAllowed) {
auto client = std::make_unique<MockHttpClient>();
EXPECT_CALL(*client, get("/users/authorized/is_allowed")).WillOnce(Return("yes"));
ApiClient api_client(std::move(client));

Request req {
.ip = "",
.uri = "",
.user = "authorized",
.ip = "127.0.0.1",
.uri = "/resource-restricted-to-authorized-users",
.user = "authorized-user",
};

HttpParams params {
{"uri", req.uri},
{"user", req.user}
};

EXPECT_CALL(*client, get("/authorized", params)).WillOnce(Return("yes"));
ApiClient api_client(std::move(client));

auto allowed = api_client.isAllowed(req);

EXPECT_THAT(allowed, true);
}

TEST(ApiClient, RequestByUnauthorizedUserIsDenied) {
auto client = std::make_unique<MockHttpClient>();
EXPECT_CALL(*client, get("/users/unauthorized/is_allowed")).WillOnce(Return("no"));
ApiClient api_client(std::move(client));

Request req {
.ip = "",
.uri = "",
.user = "unauthorized",
.ip = "127.0.0.1",
.uri = "/resource-restricted-to-authorized-users",
.user = "unauthorized-user",
};

HttpParams params {
{"uri", req.uri},
{"user", req.user}
};

EXPECT_CALL(*client, get("/authorized", params)).WillOnce(Return("no"));
ApiClient api_client(std::move(client));

auto allowed = api_client.isAllowed(req);

EXPECT_THAT(allowed, false);
Expand All @@ -64,4 +74,4 @@ TEST(ApiClient, UsesTheSuppliedApiUrl) {
<< "correct URL... pushing everything back to config and likely "
<< "a factory/builder rather than concrete class dependency.";
ApiClient client("http://api.invalid");
}
}
4 changes: 2 additions & 2 deletions apache/client/test/lauth/authorizer_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ TEST(AuthorizerTest, AllowsAccessWhenApiSaysAuthorized) {

Request req {
.ip = "",
.uri = "",
.uri = "/user/",
.user = "lauth-allowed",
};
auto allowed = authorizer.isAllowed(req);
Expand All @@ -38,7 +38,7 @@ TEST(AuthorizerTest, DeniesAccessWhenApiSaysUnauthorized) {

Request req {
.ip = "",
.uri = "",
.uri = "/user/",
.user = "lauth-denied",
};
auto allowed = authorizer.isAllowed(req);
Expand Down
22 changes: 22 additions & 0 deletions apache/client/test/lauth/http_client_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "mocks.hpp"

#include "lauth/http_client.hpp"
#include "lauth/http_params.hpp"
#include "lauth/request.hpp"

#include <string>
Expand Down Expand Up @@ -51,3 +52,24 @@ TEST(HttpClient, get_request_with_path_returns_body) {
auto response = client.get("/ping");
EXPECT_THAT(response, "pong");
}

TEST(HttpClient, GetRequestWithOneParameterEncodesIt) {
HttpClient client(MOCK_API_URL());

HttpParams params;
params.emplace("foo", "bar");
auto response = client.get("/echo", params);

EXPECT_THAT(*response, Eq(R"({"foo":"bar"})"));
}

TEST(HttpClient, GetRequestWithMultipleParametersEncodesThem) {
HttpClient client(MOCK_API_URL());

HttpParams params;
params.emplace("foo", "bar");
params.emplace("something", "else");
auto response = client.get("/echo", params);

EXPECT_THAT(*response, Eq(R"({"foo":"bar","something":"else"})"));
}
2 changes: 2 additions & 0 deletions apache/client/test/lauth/mocks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "lauth/api_client.hpp"
#include "lauth/http_client.hpp"
#include "lauth/http_params.hpp"

#include <optional>

Expand All @@ -12,6 +13,7 @@ class MockHttpClient : public HttpClient {
public:
MockHttpClient() : HttpClient("http://api.invalid") {};
MOCK_METHOD(std::optional<std::string>, get, (const std::string&), (override));
MOCK_METHOD(std::optional<std::string>, get, (const std::string&, const HttpParams&), (override));
};

class MockApiClient : public ApiClient {
Expand Down
11 changes: 11 additions & 0 deletions apache/client/test/mock_service.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include <httplib.h>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main(int argc, char **argv) {
using namespace httplib;
Expand All @@ -24,6 +27,14 @@ int main(int argc, char **argv) {
res.set_content("pong", "text/plain");
});

// Echo GET query parameters as sorted json object
server.Get("/echo", [](const Request &req, Response &res) {
json params(req.params);

std::cout << "GET /echo" << std::endl;
res.set_content(params.dump().c_str(), "application/json");
});

server.Get("/users/authorized/is_allowed", [](const Request &, Response &res) {
std::cout << "GET /users/authorized/is_allowed" << std::endl;
res.set_content("yes", "text/plain");
Expand Down

0 comments on commit 60ea186

Please sign in to comment.