Malloy
Toggle main menu visibility
Loading...
Searching...
No Matches
lib
malloy
server
auth
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
11
namespace
malloy::server::http::auth
12
{
13
namespace
detail
14
{
15
struct
auth_field
16
{
17
std::string method;
18
std::string username;
19
std::string password;
20
};
21
22
template
<
typename
D>
23
struct
base64_decoder_helper
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;
72
using
response_type =
malloy::http::response<body_type>
;
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
119
response_type
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
}
malloy::http::response
Definition
response.hpp:22
malloy::server::http::auth::detail::base64_decoder
Definition
basic.hpp:33
malloy::split
std::vector< std::string_view > split(std::string_view str, std::string_view delimiter)
Definition
utils.hpp:86
malloy::server::http::auth::detail::auth_field
Definition
basic.hpp:16
malloy::server::http::auth::detail::base64_decoder_helper
Definition
basic.hpp:24
Generated by
1.18.0