Malloy
Loading...
Searching...
No Matches
basic.hpp
1#pragma once
2
3#include "../../core/http/type_traits.hpp"
4#include "../../core/http/response.hpp"
5#include "../../core/http/generator.hpp"
6
7#include <fmt/format.h>
8
9#include <iostream>
10
11namespace malloy::server::http::auth
12{
13 namespace detail
14 {
16 {
17 std::string method;
18 std::string username;
19 std::string password;
20 };
21
22 template<typename D>
24 {
25 void operator()(std::string_view v, std::string s)
26 {
27 auto b = boost::asio::dynamic_buffer(s);
28 D::decode(v, s);
29 }
30 };
31
32 template<typename D>
33 concept base64_decoder = requires(std::string_view v, std::string s)
34 {
35 { base64_decoder_helper<D>{}(v, s) };
36 };
37
38 template<base64_decoder Decoder>
39 inline
40 std::optional<auth_field>
41 parse_auth_field(std::string_view txt)
42 {
43 auto method_pos = txt.find_first_of(' ');
44 if (method_pos == std::string::npos)
45 return std::nullopt;
46
47 auto encoded_usepass = txt.substr(method_pos+1);
48 try {
49 std::string out;
50 auto outbuff = boost::asio::dynamic_buffer(out);
51 Decoder::decode(encoded_usepass, outbuff);
52 out.erase(std::find(out.begin(), out.end(), '\0'), out.end());
53 const auto parsed_usepass = malloy::split(out, ":");
54 if (parsed_usepass.size() != 2)
55 return std::nullopt;
56
57 return auth_field{std::string{txt.begin(), txt.begin() + method_pos}, std::string{parsed_usepass.at(0)}, std::string{parsed_usepass.at(1)}};
58 }
59 catch (const std::invalid_argument&) {
60 return std::nullopt;
61 }
62 }
63 }
64
65 template<detail::base64_decoder Decoder, malloy::http::concepts::body BodyType = boost::beast::http::string_body>
66 class basic
67 {
68 static constexpr auto cli_auth_field_name = "Authorization";
69
70 public:
71 using body_type = BodyType;
73
74 basic(std::string username, std::string password, std::string realm) :
75 m_username{std::move(username)},
76 m_password{std::move(password)},
77 m_realm{std::move(realm)}
78 {
79 rebuild_www_auth_txt();
80 }
81
82 void
83 set_charset(const std::string& chset)
84 {
85 m_charset = chset;
86 rebuild_www_auth_txt();
87 }
88
89 std::optional<response_type>
90 operator()(const boost::beast::http::request_header<>& h)
91 {
92 auto auth_iter = h.find(cli_auth_field_name);
93 if (auth_iter == h.end()) {
94 // No auth header
95 return not_authed_resp();
96 }
97
98 auto maybe_parsed = detail::parse_auth_field<Decoder>(auth_iter->value());
99 if (!maybe_parsed)
100 return not_authed_resp();
101
102 const auto auth_details = std::move(*maybe_parsed);
103 const auto r1 = auth_details.method != "Basic";
104 const auto r2 = auth_details.username != m_username;
105 const auto r3 = auth_details.password != m_password;
106 if ((auth_details.method != std::string_view{"Basic"}) || (auth_details.username != m_username) || (auth_details.password != m_password))
107 return not_authed_resp();
108 else
109 return std::nullopt;
110 }
111
112 private:
113 void
114 rebuild_www_auth_txt()
115 {
116 m_www_auth = fmt::format(R"(Basic realm="{}", charset="{}")", m_realm, m_charset);
117 }
118
120 not_authed_resp()
121 {
122 response_type resp{malloy::http::status::unauthorized};
123 resp.set(malloy::http::field::www_authenticate, m_www_auth);
124
125 return resp;
126 }
127
128 std::string m_username;
129 std::string m_password;
130 std::string m_realm;
131 std::string m_www_auth;
132 std::string m_charset{"UTF-8"};
133 };
134
135}
Definition: response.hpp:22
Definition: basic.hpp:67
std::vector< std::string_view > split(std::string_view str, std::string_view delimiter)
Definition: utils.hpp:86