Kea 2.0.0
basic_auth_config.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2021 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <http/auth_log.h>
11#include <util/strutil.h>
12
13using namespace isc;
14using namespace isc::data;
15using namespace isc::dhcp;
16using namespace isc::util;
17using namespace std;
18
19namespace isc {
20namespace http {
21
23 const std::string& password,
24 const isc::data::ConstElementPtr& user_context)
25 : user_(user), password_(password) {
26 if (user_context) {
27 setContext(user_context);
28 }
29}
30
33 ElementPtr result = Element::createMap();
34
35 // Set user-context
36 contextToElement(result);
37
38 // Set user
39 result->set("user", Element::create(user_));
40
41 // Set password
42 result->set("password", Element::create(password_));
43
44 return (result);
45}
46
47void
48BasicHttpAuthConfig::add(const std::string& user,
49 const std::string& password,
50 const ConstElementPtr& user_context) {
51 BasicHttpAuth basic_auth(user, password);
52 list_.push_back(BasicHttpAuthClient(user, password, user_context));
53 map_[basic_auth.getCredential()] = user;
54}
55
56void
58 list_.clear();
59 map_.clear();
60}
61
62bool
64 return (map_.empty());
65}
66
69 ElementPtr result = Element::createMap();
70
71 // Set user-context
72 contextToElement(result);
73
74 // Set type
75 result->set("type", Element::create(string("basic")));
76
77 // Set realm
78 result->set("realm", Element::create(getRealm()));
79
80 // Set clients
81 ElementPtr clients = Element::createList();
82 for (auto client : list_) {
83 clients->add(client.toElement());
84 }
85 result->set("clients", clients);
86
87 return (result);
88}
89
90void
92 if (!config) {
93 return;
94 }
95 if (config->getType() != Element::map) {
96 isc_throw(DhcpConfigError, "authentication must be a map ("
97 << config->getPosition() << ")");
98 }
99
100 // Get and verify the type.
101 ConstElementPtr type = config->get("type");
102 if (!type) {
103 isc_throw(DhcpConfigError, "type is required in authentication ("
104 << config->getPosition() << ")");
105 }
106 if (type->getType() != Element::string) {
107 isc_throw(DhcpConfigError, "type is must be a string ("
108 << type->getPosition() << ")");
109 }
110 if (type->stringValue() != "basic") {
111 isc_throw(DhcpConfigError, "only basic HTTP authentication is "
112 << "supported: type is '" << type->stringValue()
113 << "' not 'basic' (" << type->getPosition() << ")");
114 }
115
116 // Get the realm.
117 ConstElementPtr realm = config->get("realm");
118 if (realm) {
119 if (realm->getType() != Element::string) {
120 isc_throw(DhcpConfigError, "realm is must be a string ("
121 << realm->getPosition() << ")");
122 }
123 setRealm(realm->stringValue());
124 }
125
126 // Get user context
127 ConstElementPtr user_context_cfg = config->get("user-context");
128 if (user_context_cfg) {
129 if (user_context_cfg->getType() != Element::map) {
130 isc_throw(DhcpConfigError, "user-context must be a map ("
131 << user_context_cfg->getPosition() << ")");
132 }
133 setContext(user_context_cfg);
134 }
135
136 // Get clients.
137 ConstElementPtr clients = config->get("clients");
138 if (!clients) {
139 return;
140 }
141 if (clients->getType() != Element::list) {
142 isc_throw(DhcpConfigError, "clients must be a list ("
143 << clients->getPosition() << ")");
144 }
145
146 // Iterate on clients.
147 for (auto client : clients->listValue()) {
148 if (client->getType() != Element::map) {
149 isc_throw(DhcpConfigError, "clients items must be maps ("
150 << client->getPosition() << ")");
151 }
152
153 // user
154 ConstElementPtr user_cfg = client->get("user");
155 if (!user_cfg) {
156 isc_throw(DhcpConfigError, "user is required in clients items ("
157 << client->getPosition() << ")");
158 }
159 if (user_cfg->getType() != Element::string) {
160 isc_throw(DhcpConfigError, "user must be a string ("
161 << user_cfg->getPosition() << ")");
162 }
163 string user = user_cfg->stringValue();
164 if (user.empty()) {
165 isc_throw(DhcpConfigError, "user must be not be empty ("
166 << user_cfg->getPosition() << ")");
167 }
168 if (user.find(':') != string::npos) {
169 isc_throw(DhcpConfigError, "user must not contain a ':': '"
170 << user << "' (" << user_cfg->getPosition() << ")");
171 }
172
173 // password
174 string password;
175 ConstElementPtr password_cfg = client->get("password");
176 if (password_cfg) {
177 if (password_cfg->getType() != Element::string) {
178 isc_throw(DhcpConfigError, "password must be a string ("
179 << password_cfg->getPosition() << ")");
180 }
181 password = password_cfg->stringValue();
182 }
183
184 // user context
185 ConstElementPtr user_context = client->get("user-context");
186 if (user_context) {
187 if (user_context->getType() != Element::map) {
188 isc_throw(DhcpConfigError, "user-context must be a map ("
189 << user_context->getPosition() << ")");
190 }
191 }
192
193 // add it.
194 try {
195 add(user, password, user_context);
196 } catch (const std::exception& ex) {
197 isc_throw(DhcpConfigError, ex.what() << " ("
198 << client->getPosition() << ")");
199 }
200 }
201}
202
205 const HttpRequestPtr& request) const {
206 const BasicHttpAuthMap& credentials = getCredentialMap();
207 bool authentic = false;
208 if (credentials.empty()) {
209 authentic = true;
210 } else try {
211 string value = request->getHeaderValue("Authorization");
212 // Trim space characters.
213 value = str::trim(value);
214 if (value.size() < 8) {
215 isc_throw(BadValue, "header content is too short");
216 }
217 // Get the authentication scheme which must be "basic".
218 string scheme = value.substr(0, 5);
219 str::lowercase(scheme);
220 if (scheme != "basic") {
221 isc_throw(BadValue, "not basic authentication");
222 }
223 // Skip the authentication scheme name and space characters.
224 value = value.substr(5);
225 value = str::trim(value);
226 // Verify the credential is in the list.
227 const auto it = credentials.find(value);
228 if (it != credentials.end()) {
230 .arg(it->second);
231 authentic = true;
232 } else {
234 authentic = false;
235 }
236 } catch (const HttpMessageNonExistingHeader&) {
238 } catch (const BadValue& ex) {
240 .arg(ex.what());
241 }
242 if (authentic) {
243 return (HttpResponseJsonPtr());
244 }
245 const string& realm = getRealm();
246 const string& scheme = "Basic";
247 HttpResponsePtr response =
249 response->reset();
250 response->context()->headers_.push_back(
251 HttpHeaderContext("WWW-Authenticate",
252 scheme + " realm=\"" + realm + "\""));
253 response->finalize();
254 return (boost::dynamic_pointer_cast<HttpResponseJson>(response));
255}
256
257} // end of namespace isc::http
258} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
To be removed. Please use ConfigError instead.
Basic HTTP authentication client configuration.
BasicHttpAuthClient(const std::string &user, const std::string &password, const isc::data::ConstElementPtr &user_context)
Constructor.
virtual isc::data::ElementPtr toElement() const
Unparses basic HTTP authentication client configuration.
virtual isc::data::ElementPtr toElement() const
Unparses basic HTTP authentication configuration.
void parse(const isc::data::ConstElementPtr &config)
Parses basic HTTP authentication configuration.
virtual isc::http::HttpResponseJsonPtr checkAuth(const isc::http::HttpResponseCreator &creator, const isc::http::HttpRequestPtr &request) const
Validate HTTP request.
virtual void clear()
Clear configuration.
void add(const std::string &user, const std::string &password, const isc::data::ConstElementPtr &user_context=isc::data::ConstElementPtr())
Add a client configuration.
virtual bool empty() const
Empty predicate.
const BasicHttpAuthMap & getCredentialMap() const
Returns the credential and user id map.
Represents a basic HTTP authentication.
Definition: basic_auth.h:21
const std::string & getCredential() const
Returns the credential (base64 of the UTF-8 secret).
Definition: basic_auth.h:43
const std::string & getRealm() const
Returns the realm.
Definition: auth_config.h:39
void setRealm(const std::string &realm)
Set the realm.
Definition: auth_config.h:32
Exception thrown when attempt is made to retrieve a non-existing header.
Definition: http_message.h:30
Specifies an interface for classes creating HTTP responses from HTTP requests.
virtual HttpResponsePtr createStockHttpResponse(const HttpRequestPtr &request, const HttpStatusCode &status_code) const =0
Creates implementation specific HTTP response.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
std::unordered_map< std::string, std::string > BasicHttpAuthMap
Type of basic HTTP authentication credential and user id map, e.g.
const isc::log::MessageID HTTP_CLIENT_REQUEST_NOT_AUTHORIZED
Definition: auth_messages.h:13
boost::shared_ptr< HttpResponseJson > HttpResponseJsonPtr
Pointer to the HttpResponseJson object.
Definition: response_json.h:24
const isc::log::MessageID HTTP_CLIENT_REQUEST_BAD_AUTH_HEADER
Definition: auth_messages.h:12
const isc::log::MessageID HTTP_CLIENT_REQUEST_AUTHORIZED
Definition: auth_messages.h:11
boost::shared_ptr< HttpResponse > HttpResponsePtr
Pointer to the HttpResponse object.
Definition: response.h:78
const isc::log::MessageID HTTP_CLIENT_REQUEST_NO_AUTH_HEADER
Definition: auth_messages.h:14
boost::shared_ptr< HttpRequest > HttpRequestPtr
Pointer to the HttpRequest object.
Definition: request.h:27
isc::log::Logger auth_logger("auth")
Defines the logger used by the HTTP authentication.
Definition: auth_log.h:18
void lowercase(std::string &text)
Lowercase String.
Definition: strutil.h:151
string trim(const string &instring)
Trim Leading and Trailing Spaces.
Definition: strutil.cc:53
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.
void contextToElement(data::ElementPtr map) const
Merge unparse a user_context object.
Definition: user_context.cc:15
void setContext(const data::ConstElementPtr &ctx)
Sets user context.
Definition: user_context.h:30
HTTP header context.