"http-host": "127.0.0.1",
"http-port": 8000,
- "basic-authentication-realm": "kea-control-agent",
- // In basic HTTP authentication
- "basic-authentications":
- [
- {
- "comment": "admin is authorized",
- "user": "admin",
- "password": "1234"
- }
- ],
+ // In authentication
+ "authentication":
+ {
+ "comment": "basic HTTP authentication",
+
+ // In basic HTTP authentication clients
+ "clients":
+ [
+ {
+ "comment": "admin is authorized",
+ "user": "admin",
+ "password": "1234"
+ }
+ ]
+ },
// In control socket
"control-sockets":
// Another mandatory parameter is the HTTP port.
"http-port": 8000,
- // An optional parameter is the basic HTTP authentication realm.
- // Its default is "kea-control-agent".
- "basic-authentication-realm": "kea-control-agent",
+ // Optional authentication.
+ "authentication":
+ {
+ // Required authentication type. The only supported value is
+ // basic for the basic HTTP authentication.
+ "type": "basic",
- // This list specifies the user ids and passwords to use for
- // basic HTTP authentication. If empty or not present any client
- // is authorized.
- "basic-authentications":
- [
- // This specifies an authorized client.
- {
- "comment": "admin is authorized",
+ // An optional parameter is the basic HTTP authentication realm.
+ // Its default is "kea-control-agent".
+ "realm": "kea-control-agent",
- // The user id must not be empty or contain the ':' character.
- // It is a mandatory parameter.
- "user": "admin",
+ // This list specifies the user ids and passwords to use for
+ // basic HTTP authentication. If empty or not present any client
+ // is authorized.
+ "clients":
+ [
+ // This specifies an authorized client.
+ {
+ "comment": "admin is authorized",
- // If password is not specified an empty password is used.
- "password": "1234"
- }
- ],
+ // The user id must not be empty or contain the ':'
+ // character. It is a mandatory parameter.
+ "user": "admin",
+
+ // If password is not specified an empty password is used.
+ "password": "1234"
+ }
+ ]
+ },
// This map specifies where control channel of each server is configured
// to listen on. See 'control-socket' object in the respective
"Control-agent": {
"http-host": "10.20.30.40",
"http-port": 8000,
- "basic-authentication-realm": "kea-control-agent",
+ "authentication": {
+ "type": "basic",
+ "realm": "kea-control-agent",
+ "clients": [
+ {
+ "user": "admin",
+ "password": "1234"
+ } ]
+ },
"control-sockets": {
"dhcp4": {
},
},
- "basic-authentications": [
- {
- "user": "admin",
- "password": "1234"
- } ],
-
"hooks-libraries": [
{
"library": "/opt/local/control-agent-commands.so",
protection against remote attackers HTTPS and reverse proxy of
:ref:`agent-secure-connection` provide a stronger security.
-The ``basic-authentication-realm`` is used for error message when
-the basic HTTP authentication is mandatory but the client is not
+The authentication is described in the ``authentication`` block
+with the mandatory ``type`` parameter which selects the authentication.
+Currently only the basic HTTP authentication (type basic) is supported.
+
+The ``realm`` authentication parameter is used for error message when
+the basic HTTP authentication is required but the client is not
authorized.
-When the ``basic-authentications`` list is configured and not empty
+When the ``clients`` authentication list is configured and not empty
the basic HTTP authentication is required. Each element of the list
specifies a user id and a password. The user id is mandatory, must
be not empty and must not contain the colon (:) character. The
\"user-context\" {
switch(driver.ctx_) {
case ParserContext::AGENT:
+ case ParserContext::AUTHENTICATION;
+ case ParserContext::CLIENTS:
case ParserContext::SERVER:
case ParserContext::LOGGERS:
- case ParserContext::CLIENTS:
return AgentParser::make_USER_CONTEXT(driver.loc_);
default:
return AgentParser::make_STRING("user-context", driver.loc_);
\"comment\" {
switch(driver.ctx_) {
case ParserContext::AGENT:
+ case ParserContext::AUTHENTICATION;
+ case ParserContext::CLIENTS:
case ParserContext::SERVER:
case ParserContext::LOGGERS:
- case ParserContext::CLIENTS:
return AgentParser::make_COMMENT(driver.loc_);
default:
return AgentParser::make_STRING("comment", driver.loc_);
#line 529 "agent_parser.yy"
{
// Add unique here
- ctx.enter(ctx.NO_KEYWORD);
+ ctx.enter(ctx.NO_KEYWORDS);
}
#line 1275 "agent_parser.cc"
break;
auth_param: auth_type
| realm
| clients
+ | comment
+ | user_context
+ | unknown_map_entry
;
auth_type: TYPE {
realm: REALM {
// Add unique here
- ctx.enter(ctx.NO_KEYWORD);
+ ctx.enter(ctx.NO_KEYWORDS);
} COLON STRING {
ElementPtr realm(new StringElement($4, ctx.loc2pos(@4)));
ctx.stack_.back()->set("realm", realm);
#include <agent/simple_parser.h>
#include <cc/simple_parser.h>
#include <cc/command_interpreter.h>
+#include <http/basic_auth_config.h>
#include <exceptions/exceptions.h>
using namespace isc::config;
namespace agent {
CtrlAgentCfgContext::CtrlAgentCfgContext()
- : http_host_(""), http_port_(0), basic_auth_realm_("") {
+ : http_host_(""), http_port_(0) {
}
CtrlAgentCfgContext::CtrlAgentCfgContext(const CtrlAgentCfgContext& orig)
: ConfigBase(), ctrl_sockets_(orig.ctrl_sockets_),
http_host_(orig.http_host_), http_port_(orig.http_port_),
- basic_auth_realm_(orig.basic_auth_realm_),
- hooks_config_(orig.hooks_config_),
- basic_auth_config_(orig.basic_auth_config_) {
+ hooks_config_(orig.hooks_config_), auth_config_(orig.auth_config_) {
}
CtrlAgentCfgMgr::CtrlAgentCfgMgr()
s << ctx->getControlSocketInfoSummary();
// Add something if authentication is required.
- const isc::http::BasicHttpAuthConfig& auth = ctx->getBasicAuthConfig();
- if (!auth.getClientList().empty()) {
+ const isc::http::HttpAuthConfigPtr& auth = ctx->getAuthConfig();
+ if (auth && !auth->empty()) {
s << ", requires basic HTTP authentication";
}
ca->set("http-host", Element::create(http_host_));
// Set http-port
ca->set("http-port", Element::create(static_cast<int64_t>(http_port_)));
- // Set basic-authentication-realm
- ca->set("basic-authentication-realm", Element::create(basic_auth_realm_));
- // Set hooks-libraries
+ // Set authentication
+ if (auth_config_) {
+ ca->set("authentication", auth_config_->toElement());
+ }
ca->set("hooks-libraries", hooks_config_.toElement());
// Set control-sockets
ElementPtr control_sockets = Element::createMap();
control_sockets->set(si->first, socket);
}
ca->set("control-sockets", control_sockets);
- // Set basic HTTP authentication
- const isc::http::BasicHttpAuthConfig& auth = basic_auth_config_;
- if (!basic_auth_config_.getClientList().empty()) {
- ca->set("basic-authentications", basic_auth_config_.toElement());
- }
// Set Control-agent
ElementPtr result = Element::createMap();
result->set("Control-agent", ca);
#include <cc/data.h>
#include <hooks/hooks_config.h>
-#include <http/basic_auth_config.h>
+#include <http/auth_config.h>
#include <process/d_cfg_mgr.h>
#include <boost/pointer_cast.hpp>
#include <map>
return (http_port_);
}
- /// @brief Sets basic-authentication-realm parameter
+ /// @brief Sets HTTP authentication configuration.
///
- /// @param real Basic HTTP authentication realm
- void setBasicAuthRealm(const std::string& realm) {
- basic_auth_realm_ = realm;
+ /// @note Only the basic HTTP authentication is supported.
+ ///
+ /// @param auth_config HTTP authentication configuration.
+ void setAuthConfig(const isc::http::HttpAuthConfigPtr& auth_config) {
+ auth_config_ = auth_config;
}
- /// @brief Returns basic-authentication-realm parameter
+ /// @brief Returns HTTP authentication configuration
+ ///
+ /// @note Only the basic HTTP authentication is supported.
///
- /// @return Basic HTTP authentication realm.
- std::string getBasicAuthRealm() const {
- return (basic_auth_realm_);
+ /// @return HTTP authentication configuration.
+ const isc::http::HttpAuthConfigPtr& getAuthConfig() const {
+ return (auth_config_);
}
/// @brief Returns non-const reference to configured hooks libraries.
return (hooks_config_);
}
- /// @brief Returns non-const reference to configured basic HTTP
- /// authentification clients.
- ///
- /// @return non-const reference to configured basic auth clients.
- isc::http::BasicHttpAuthConfig& getBasicAuthConfig() {
- return (basic_auth_config_);
- }
-
- /// @brief Returns const reference to configured basic HTTP
- /// authentification clients.
- ///
- /// @return const reference to configured basic auth clients.
- const isc::http::BasicHttpAuthConfig& getBasicAuthConfig() const {
- return (basic_auth_config_);
- }
-
/// @brief Unparse a configuration object
///
/// Returns an element which must parse into the same object, i.e.
/// TCP port the CA should listen on.
uint16_t http_port_;
- /// Basic HTTP authentication realm.
- std::string basic_auth_realm_;
-
/// @brief Configured hooks libraries.
isc::hooks::HooksConfig hooks_config_;
/// @brief Configured basic HTTP authentification clients.
- isc::http::BasicHttpAuthConfig basic_auth_config_;
+ isc::http::HttpAuthConfigPtr auth_config_;
};
/// @brief Ctrl Agent Configuration Manager.
#include <agent/ca_response_creator.h>
#include <cc/data.h>
#include <http/post_request_json.h>
-#include <http/response_creator_auth.h>
#include <http/response_json.h>
#include <boost/pointer_cast.hpp>
#include <iostream>
if (cfgmgr) {
ctx = cfgmgr->getCtrlAgentCfgContext();
if (ctx) {
- const BasicHttpAuthConfig& auth = ctx->getBasicAuthConfig();
- const BasicHttpAuthMap& auth_map = auth.getCredentialMap();
- // Check authentication.
- http_response = checkAuth(*this, request, auth_map,
- ctx->getBasicAuthRealm());
+ const HttpAuthConfigPtr& auth = ctx->getAuthConfig();
+ if (auth) {
+ // Check authentication.
+ http_response = auth->checkAuth(*this, request);
+ }
}
}
}
return (isc::data::Element::Position(file, line, pos));
}
+void
+ParserContext::require(const std::string& name,
+ isc::data::Element::Position open_loc,
+ isc::data::Element::Position close_loc)
+{
+ ConstElementPtr value = stack_.back()->get(name);
+ if (!value) {
+ isc_throw(ParseError,
+ "missing parameter '" << name << "' ("
+ << stack_.back()->getPosition() << ") ["
+ << contextName() << " map between "
+ << open_loc << " and " << close_loc << "]");
+ }
+}
+
void
ParserContext::enter(const LexerContext& ctx)
{
/// @return Position in format accepted by Element
isc::data::Element::Position loc2pos(isc::agent::location& loc);
+ /// @brief Check if a required parameter is present
+ ///
+ /// Check if a required parameter is present in the map at the top
+ /// of the stack and raise an error when it is not.
+ ///
+ /// @param name name of the parameter to check
+ /// @param open_loc location of the opening curly bracket
+ /// @param close_loc location of the closing curly bracket
+ /// @throw ParseError
+ void require(const std::string& name,
+ isc::data::Element::Position open_loc,
+ isc::data::Element::Position close_loc);
+
/// @brief Defines syntactic contexts for lexical tie-ins
typedef enum {
///< This one is used in pure JSON mode.
#include <cc/dhcp_config_error.h>
#include <hooks/hooks_manager.h>
#include <hooks/hooks_parser.h>
+#include <http/basic_auth_config.h>
#include <boost/foreach.hpp>
using namespace isc::data;
///
/// These are global Control Agent parameters.
const SimpleDefaults AgentSimpleParser::AGENT_DEFAULTS = {
- { "http-host", Element::string, "127.0.0.1" },
- { "http-port", Element::integer, "8000" },
- { "basic-authentication-realm", Element::string, "kea-control-agent" }
+ { "http-host", Element::string, "127.0.0.1" },
+ { "http-port", Element::integer, "8000" }
+};
+
+/// @brief This table defines default values for authentication.
+const SimpleDefaults AgentSimpleParser::AUTH_DEFAULTS = {
+ { "type", Element::string, "basic" },
+ { "realm", Element::string, "kea-control-agent" }
};
/// @brief This table defines default values for control sockets.
///
const SimpleDefaults AgentSimpleParser::SOCKET_DEFAULTS = {
- { "socket-type", Element::string, "unix"}
+ { "socket-type", Element::string, "unix" }
};
/// @}
// Set global defaults first.
cnt = setDefaults(global, AGENT_DEFAULTS);
+ // After set the defaults for authentication if it exists.
+ ConstElementPtr authentication = global->get("authentication");
+ if (authentication) {
+ ElementPtr auth = boost::const_pointer_cast<Element>(authentication);
+ if (auth) {
+ cnt += SimpleParser::setDefaults(auth, AUTH_DEFAULTS);
+ }
+ }
+
// Now set the defaults for control-sockets, if any.
ConstElementPtr sockets = global->get("control-sockets");
if (sockets) {
// Let's get the HTTP parameters first.
ctx->setHttpHost(SimpleParser::getString(config, "http-host"));
ctx->setHttpPort(SimpleParser::getIntType<uint16_t>(config, "http-port"));
- ctx->setBasicAuthRealm(SimpleParser::getString(config,
- "basic-authentication-realm"));
// Control sockets are second.
ConstElementPtr ctrl_sockets = config->get("control-sockets");
}
// Basic HTTP authentications are third.
- ConstElementPtr auth_config = config->get("basic-authentications");
- ctx->getBasicAuthConfig().clear();
- ctx->getBasicAuthConfig().parse(auth_config);
+ ConstElementPtr auth_config = config->get("authentications");
+ if (auth_config) {
+ using namespace isc::http;
+ BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
+ auth->parse(auth_config);
+ ctx->setAuthConfig(auth);
+ }
// User context can be done at anytime.
ConstElementPtr user_context = config->get("user-context");
}
// Finally, let's get the hook libs!
-
using namespace isc::hooks;
HooksConfig& libraries = ctx->getHooksConfig();
ConstElementPtr hooks = config->get("hooks-libraries");
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2020 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// see simple_parser.cc for comments for those parameters
static const isc::data::SimpleDefaults AGENT_DEFAULTS;
+ static const isc::data::SimpleDefaults AUTH_DEFAULTS;
static const isc::data::SimpleDefaults SOCKET_DEFAULTS;
};
-};
-};
+}
+}
#endif
#include <exceptions/exceptions.h>
#include <process/testutils/d_test_stubs.h>
#include <process/d_cfg_mgr.h>
+#include <http/basic_auth_config.h>
#include <agent/tests/test_libraries.h>
+#include <boost/pointer_cast.hpp>
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
ctx.setHttpHost("alnitak");
EXPECT_EQ("alnitak", ctx.getHttpHost());
-
- ctx.setBasicAuthRealm("foobar");
- EXPECT_EQ("foobar", ctx.getBasicAuthRealm());
}
// Tests if context can store and retrieve control socket information.
EXPECT_NO_THROW(ctx.setHttpPort(12345));
EXPECT_NO_THROW(ctx.setHttpHost("bellatrix"));
- EXPECT_NO_THROW(ctx.setBasicAuthRealm("foobar"));
HooksConfig& libs = ctx.getHooksConfig();
string exp_name("testlib1.so");
ConstElementPtr exp_param(new StringElement("myparam"));
libs.add(exp_name, exp_param);
- BasicHttpAuthConfig& auth = ctx.getBasicAuthConfig();
- auth.add("foo", "bar");
+ BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
+ auth->setRealm("foobar");
+ auth->add("foo", "bar");
+ EXPECT_NO_THROW(ctx.setAuthConfig(auth));
// Make a copy.
ConfigPtr copy_base(ctx.clone());
// Now check the values returned
EXPECT_EQ(12345, copy->getHttpPort());
EXPECT_EQ("bellatrix", copy->getHttpHost());
- EXPECT_EQ("foobar", copy->getBasicAuthRealm());
// Check socket info
ASSERT_TRUE(copy->getControlSocketInfo("d2"));
ASSERT_TRUE(libs2[0].second);
EXPECT_EQ(exp_param->str(), libs2[0].second->str());
- // Check basic HTTP authentication
- const BasicHttpAuthConfig& auth2 = copy->getBasicAuthConfig();
- EXPECT_EQ(auth.toElement()->str(), auth2.toElement()->str());
+ // Check authentication
+ const HttpAuthConfigPtr& auth2 = copy->getAuthConfig();
+ ASSERT_TRUE(auth2);
+ EXPECT_EQ(auth->toElement()->str(), auth2->toElement()->str());
}
EXPECT_EQ(libs.get(), stored_libs.get());
}
-// Test if the context can store and retrieve basic HTTP authentication clients.
-TEST(CtrlAgentCfgMgr, contextBasicAuth) {
+// Test if the context can store and retrieve basic HTTP authentication
+// configuration.
+TEST(CtrlAgentCfgMgr, contextAuthConfig) {
CtrlAgentCfgContext ctx;
// By default there should be no authentication.
- BasicHttpAuthConfig& auth = ctx.getBasicAuthConfig();
- EXPECT_TRUE(auth.getClientList().empty());
-
- auth.add("foo", "bar");
- auth.add("test", "123\xa3");
-
- const BasicHttpAuthConfig& stored_auth = ctx.getBasicAuthConfig();
- EXPECT_EQ(2, stored_auth.getClientList().size());
-
- EXPECT_EQ(auth.toElement()->str(), stored_auth.toElement()->str());
+ EXPECT_FALSE(ctx.getAuthConfig());
+ BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
+ EXPECT_NO_THROW(ctx.setAuthConfig(auth));
+
+ auth->setRealm("foobar");
+ auth->add("foo", "bar");
+ auth->add("test", "123\xa3");
+
+ const HttpAuthConfigPtr& stored_auth = ctx.getAuthConfig();
+ ASSERT_TRUE(stored_auth);
+ EXPECT_FALSE(stored_auth->empty());
+ EXPECT_EQ(auth->toElement()->str(), stored_auth->toElement()->str());
}
/// Control Agent configurations used in tests.
// Configuration 1: http parameters only (no control sockets, not hooks)
"{ \"http-host\": \"betelgeuse\",\n"
- " \"http-port\": 8001,\n"
- " \"basic-authentication-realm\": \"foobar\"\n"
+ " \"http-port\": 8001\n"
"}",
// Configuration 2: http and 1 socket
"{\n"
" \"http-host\": \"betelgeuse\",\n"
" \"http-port\": 8001,\n"
- " \"basic-authentication-realm\": \"foobar\",\n"
" \"control-sockets\": {\n"
" \"dhcp4\": {\n"
" \"socket-name\": \"/tmp/socket-v4\"\n"
"{\n"
" \"http-host\": \"betelgeuse\",\n"
" \"http-port\": 8001,\n"
- " \"basic-authentication-realm\": \"foobar\",\n"
" \"control-sockets\": {\n"
" \"dhcp4\": {\n"
" \"socket-name\": \"/tmp/socket-v4\"\n"
"{\n"
" \"http-host\": \"betelgeuse\",\n"
" \"http-port\": 8001,\n"
- " \"basic-authentication-realm\": \"foobar\",\n"
" \"control-sockets\": {\n"
" \"dhcp4\": {\n"
" \"socket-name\": \"/tmp/socket-v4\"\n"
"{\n"
" \"http-host\": \"betelgeuse\",\n"
" \"http-port\": 8001,\n"
- " \"basic-authentication-realm\": \"foobar\",\n"
" \"control-sockets\": {\n"
" \"d2\": {\n"
" \"socket-name\": \"/tmp/socket-d2\"\n"
"{\n"
" \"http-host\": \"betelgeuse\",\n"
" \"http-port\": 8001,\n"
- " \"basic-authentication-realm\": \"foobar\",\n"
" \"control-sockets\": {\n"
" \"dhcp6\": {\n"
" \"socket-name\": \"/tmp/socket-v6\"\n"
" }\n"
"}",
- // Configuration 7: http, 1 socket and basic authentication
+ // Configuration 7: http, 1 socket and authentication
"{\n"
" \"http-host\": \"betelgeuse\",\n"
" \"http-port\": 8001,\n"
- " \"basic-authentication-realm\": \"foobar\",\n"
+ " \"authentication\": {\n"
+ " \"type\": \"basic\",\n"
+ " \"realm\": \"foobar\",\n"
+ " \"clients\": ["
+ " {"
+ " \"user\": \"foo\",\n"
+ " \"password\": \"bar\"\n"
+ " },{\n"
+ " \"user\": \"test\",\n"
+ " \"password\": \"123\\u00a3\"\n"
+ " }\n"
+ " ]\n"
+ " },\n"
" \"control-sockets\": {\n"
" \"dhcp4\": {\n"
" \"socket-name\": \"/tmp/socket-v4\"\n"
" }\n"
- " },\n"
- " \"basic-authentications\": ["
- " {"
- " \"user\": \"foo\",\n"
- " \"password\": \"bar\"\n"
- " },{\n"
- " \"user\": \"test\",\n"
- " \"password\": \"123\\u00a3\"\n"
- " }\n"
- " ]\n"
+ " }\n"
"}",
// Configuration 8: http and 2 sockets with user contexts and comments
" \"user-context\": { \"comment\": \"Indirect comment\" },\n"
" \"http-host\": \"betelgeuse\",\n"
" \"http-port\": 8001,\n"
- " \"basic-authentication-realm\": \"foobar\",\n"
+ " \"authentication\": {\n"
+ " \"comment\": \"basic HTTP authentication\",\n"
+ " \"type\": \"basic\",\n"
+ " \"realm\": \"foobar\",\n"
+ " \"clients\": ["
+ " {"
+ " \"comment\": \"foo is authorized\",\n"
+ " \"user\": \"foo\",\n"
+ " \"password\": \"bar\"\n"
+ " },{\n"
+ " \"user\": \"test\",\n"
+ " \"user-context\": { \"no password\": true }\n"
+ " }\n"
+ " ]\n"
+ " },\n"
" \"control-sockets\": {\n"
" \"dhcp4\": {\n"
" \"comment\": \"dhcp4 socket\",\n"
" \"socket-name\": \"/tmp/socket-v6\",\n"
" \"user-context\": { \"version\": 1 }\n"
" }\n"
- " },\n"
- " \"basic-authentications\": ["
- " {"
- " \"comment\": \"foo is authorized\",\n"
- " \"user\": \"foo\",\n"
- " \"password\": \"bar\"\n"
- " },{\n"
- " \"user\": \"test\",\n"
- " \"user-context\": { \"no password\": true }\n"
- " }\n"
- " ]\n"
+ " }\n"
"}"
};
ASSERT_TRUE(ctx);
EXPECT_EQ("betelgeuse", ctx->getHttpHost());
EXPECT_EQ(8001, ctx->getHttpPort());
- EXPECT_EQ("foobar", ctx->getBasicAuthRealm());
}
// Tests if a single socket can be configured. BTW this test also checks
// This test checks that the config file with basic HTTP authentication can be
// loaded.
-TEST_F(AgentParserTest, configParseBasicAuth) {
+TEST_F(AgentParserTest, configParseAuth) {
configParse(AGENT_CONFIGS[7], 0);
CtrlAgentCfgContextPtr ctx = cfg_mgr_.getCtrlAgentCfgContext();
- const BasicHttpAuthConfig& auth = ctx->getBasicAuthConfig();
+ const HttpAuthConfigPtr& auth = ctx->getAuthConfig();
+ ASSERT_TRUE(auth);
+ const BasicHttpAuthConfigPtr& basic_auth =
+ boost::dynamic_pointer_cast<BasicHttpAuthConfig>(auth);
+ ASSERT_TRUE(basic_auth);
+
+ // Check realm
+ EXPECT_EQ("foobar", basic_auth->getRealm());
// Check credentails
- auto credentials = auth.getCredentialMap();
+ auto credentials = basic_auth->getCredentialMap();
EXPECT_EQ(2, credentials.size());
std::string user;
EXPECT_NO_THROW(user = credentials.at("Zm9vOmJhcg=="));
// Check clients.
BasicHttpAuthConfig expected;
+ expected.setRealm("foobar");
expected.add("foo", "bar");
expected.add("test", "123\xa3");
- EXPECT_EQ(expected.toElement()->str(), auth.toElement()->str());
+ EXPECT_EQ(expected.toElement()->str(), basic_auth->toElement()->str());
}
// This test checks comments.
ASSERT_TRUE(ctx6->get("version"));
EXPECT_EQ("1", ctx6->get("version")->str());
- // Check basic HTTP authentication comment.
- const BasicHttpAuthConfig& auth = agent_ctx->getBasicAuthConfig();
- auto clients = auth.getClientList();
- ASSERT_EQ(2, clients.size());
- ConstElementPtr ctx7 = clients.front().getContext();
+ // Check authentication comment.
+ const HttpAuthConfigPtr& auth = agent_ctx->getAuthConfig();
+ ASSERT_TRUE(auth);
+ ConstElementPtr ctx7 = auth->getContext();
ASSERT_TRUE(ctx7);
ASSERT_EQ(1, ctx7->size());
ASSERT_TRUE(ctx7->get("comment"));
- EXPECT_EQ("\"foo is authorized\"", ctx7->get("comment")->str());
+ EXPECT_EQ("\"basic HTTP authentication\"", ctx7->get("comment")->str());
- // Check basic HTTP authentication user context.
- ConstElementPtr ctx8 = clients.back().getContext();
+ // Check basic HTTP authentication client comment.
+ const BasicHttpAuthConfigPtr& basic_auth =
+ boost::dynamic_pointer_cast<BasicHttpAuthConfig>(auth);
+ ASSERT_TRUE(basic_auth);
+ auto clients = basic_auth->getClientList();
+ ASSERT_EQ(2, clients.size());
+ ConstElementPtr ctx8 = clients.front().getContext();
ASSERT_TRUE(ctx8);
ASSERT_EQ(1, ctx8->size());
- ASSERT_TRUE(ctx8->get("no password"));
- EXPECT_EQ("true", ctx8->get("no password")->str());
+ ASSERT_TRUE(ctx8->get("comment"));
+ EXPECT_EQ("\"foo is authorized\"", ctx8->get("comment")->str());
+
+ // Check basic HTTP authentication client user context.
+ ConstElementPtr ctx9 = clients.back().getContext();
+ ASSERT_TRUE(ctx9);
+ ASSERT_EQ(1, ctx9->size());
+ ASSERT_TRUE(ctx9->get("no password"));
+ EXPECT_EQ("true", ctx9->get("no password")->str());
}
} // end of anonymous namespace
#include <agent/ca_command_mgr.h>
#include <agent/ca_response_creator.h>
#include <cc/command_interpreter.h>
+#include <http/basic_auth_config.h>
#include <http/post_request.h>
#include <http/post_request_json.h>
#include <http/response_json.h>
// Require authentication.
CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
ASSERT_TRUE(ctx);
- ctx->setBasicAuthRealm("ISC.ORG");
- BasicHttpAuthConfig& auth = ctx->getBasicAuthConfig();
- auth.add("foo", "bar");
+ BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
+ ASSERT_NO_THROW(ctx->setAuthConfig(auth));
+ auth->setRealm("ISC.ORG");
+ auth->add("foo", "bar");
HttpResponsePtr response;
ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
// Require authentication.
CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
ASSERT_TRUE(ctx);
- BasicHttpAuthConfig& auth = ctx->getBasicAuthConfig();
- auth.add("foo", "bar");
+ BasicHttpAuthConfigPtr auth(new BasicHttpAuthConfig());
+ ASSERT_NO_THROW(ctx->setAuthConfig(auth));
+ // In fact the realm is used only on errors... set it anyway.
+ auth->setRealm("ISC.ORG");
+ auth->add("foo", "bar");
HttpResponsePtr response;
ASSERT_NO_THROW(response = response_creator_.createHttpResponse(request_));
libkea_http_la_SOURCES += response_parser.cc response_parser.h
libkea_http_la_SOURCES += response_context.h
libkea_http_la_SOURCES += response_creator.cc response_creator.h
-libkea_http_la_SOURCES += response_creator_auth.cc response_creator_auth.h
libkea_http_la_SOURCES += response_creator_factory.h
libkea_http_la_SOURCES += response_json.cc response_json.h
libkea_http_la_SOURCES += url.cc url.h
libkea_http_la_SOURCES += basic_auth.cc basic_auth.h
+libkea_http_la_SOURCES += auth_config.h
libkea_http_la_SOURCES += basic_auth_config.cc basic_auth_config.h
libkea_http_la_CXXFLAGS = $(AM_CXXFLAGS)
# Specify the headers for copying into the installation directory tree.
libkea_http_includedir = $(pkgincludedir)/http
libkea_http_include_HEADERS = \
+ auth_config.h \
basic_auth.h \
basic_auth_config.h \
client.h \
response.h \
response_context.h \
response_creator.h \
- response_creator_auth.h \
response_creator_factory.h \
response_json.h \
response_parser.h \
--- /dev/null
+// Copyright (C) 2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef HTTP_AUTH_CONFIG_H
+#define HTTP_AUTH_CONFIG_H
+
+#include <cc/cfg_to_element.h>
+#include <cc/data.h>
+#include <cc/simple_parser.h>
+#include <cc/user_context.h>
+#include <http/request.h>
+#include <http/response_creator.h>
+#include <http/response_json.h>
+
+namespace isc {
+namespace http {
+
+/// @brief Base type of HTTP authentication configuration.
+class HttpAuthConfig : public isc::data::UserContext,
+ public isc::data::CfgToElement {
+public:
+
+ /// @brief Destructor.
+ virtual ~HttpAuthConfig() { }
+
+ /// @brief Set the realm.
+ ///
+ /// @param realm New realm.
+ void setRealm(const std::string& realm) {
+ realm_ = realm;
+ }
+
+ /// @brief Returns the realm.
+ ///
+ /// @return The basic HTTP authentication realm.
+ const std::string& getRealm() const {
+ return (realm_);
+ }
+
+ /// @brief Empty predicate.
+ /// @return true if the configuration is empty so authentication
+ /// is not required.
+ virtual bool empty() const = 0;
+
+ /// @brief Clear configuration.
+ virtual void clear() = 0;
+
+ /// @brief Parses HTTP authentication configuration.
+ ///
+ /// @param config Element holding the basic HTTP authentication
+ /// configuration to be parsed.
+ /// @throw DhcpConfigError when the configuration is invalid.
+ virtual void parse(const isc::data::ConstElementPtr& config) = 0;
+
+ /// @brief Unparses HTTP authentication configuration.
+ ///
+ /// @return A pointer to unparsed HTTP authentication configuration.
+ virtual isc::data::ElementPtr toElement() const = 0;
+
+ /// @brief Validate HTTP request.
+ ///
+ /// @param creator The HTTP response creator.
+ /// @param request The HTTP request to validate.
+ /// @return Error HTTP response if validation failed, null otherwise.
+ virtual isc::http::HttpResponseJsonPtr
+ checkAuth(const isc::http::HttpResponseCreator& creator,
+ const isc::http::ConstHttpRequestPtr& request) const = 0;
+
+private:
+
+ /// @brief The realm.
+ std::string realm_;
+};
+
+/// @brief Type of shared pointers to HTTP authentication configuration.
+typedef boost::shared_ptr<HttpAuthConfig> HttpAuthConfigPtr;
+
+} // end of namespace isc::http
+} // end of namespace isc
+
+#endif // endif HTTP_AUTH_CONFIG_H
#include <config.h>
#include <http/basic_auth_config.h>
+#include <http/http_log.h>
+#include <util/strutil.h>
using namespace isc;
using namespace isc::data;
using namespace isc::dhcp;
+using namespace isc::util;
using namespace std;
namespace isc {
map_.clear();
}
+bool
+BasicHttpAuthConfig::empty() const {
+ return (map_.empty());
+}
+
ElementPtr
BasicHttpAuthConfig::toElement() const {
- ElementPtr result = Element::createList();
+ ElementPtr result = Element::createMap();
+
+ // Set user-context
+ contextToElement(result);
+
+ // Set type
+ result->set("type", Element::create(string("basic")));
+
+ // Set realm
+ result->set("realm", Element::create(getRealm()));
+ // Set clients
+ ElementPtr clients = Element::createList();
for (auto client : list_) {
- result->add(client.toElement());
+ clients->add(client.toElement());
}
+ result->set("clients", clients);
return (result);
}
if (!config) {
return;
}
- if (config->getType() != Element::list) {
- isc_throw(DhcpConfigError, "basic-authentications must be a list ("
+ if (config->getType() != Element::map) {
+ isc_throw(DhcpConfigError, "authentication must be a map ("
<< config->getPosition() << ")");
}
- for (auto client : config->listValue()) {
+
+ // Get and verify the type.
+ ConstElementPtr type = config->get("type");
+ if (!type) {
+ isc_throw(DhcpConfigError, "type is required in authentication ("
+ << config->getPosition() << ")");
+ }
+ if (type->getType() != Element::string) {
+ isc_throw(DhcpConfigError, "type is must be a string ("
+ << type->getPosition() << ")");
+ }
+ if (type->stringValue() != "basic") {
+ isc_throw(DhcpConfigError, "only basic HTTP authentication is "
+ << "supported: type is '" << type->stringValue()
+ << "' not 'basic' (" << type->getPosition() << ")");
+ }
+
+ // Get the realm.
+ ConstElementPtr realm = config->get("realm");
+ if (realm) {
+ if (realm->getType() != Element::string) {
+ isc_throw(DhcpConfigError, "realm is must be a string ("
+ << realm->getPosition() << ")");
+ }
+ setRealm(realm->stringValue());
+ }
+
+ // Get user context
+ ConstElementPtr user_context_cfg = config->get("user-context");
+ if (user_context_cfg) {
+ if (user_context_cfg->getType() != Element::map) {
+ isc_throw(DhcpConfigError, "user-context must be a map ("
+ << user_context_cfg->getPosition() << ")");
+ }
+ setContext(user_context_cfg);
+ }
+
+ // Get clients.
+ ConstElementPtr clients = config->get("clients");
+ if (!clients) {
+ return;
+ }
+ if (clients->getType() != Element::list) {
+ isc_throw(DhcpConfigError, "clients must be a list ("
+ << clients->getPosition() << ")");
+ }
+
+ // Iterate on clients.
+ for (auto client : clients->listValue()) {
if (client->getType() != Element::map) {
- isc_throw(DhcpConfigError, "basic-authentications items must be "
- << "maps (" << client->getPosition() << ")");
+ isc_throw(DhcpConfigError, "clients items must be maps ("
+ << client->getPosition() << ")");
}
// user
ConstElementPtr user_cfg = client->get("user");
if (!user_cfg) {
- isc_throw(DhcpConfigError, "user is required in "
- << "basic-authentications items ("
+ isc_throw(DhcpConfigError, "user is required in clients items ("
<< client->getPosition() << ")");
}
if (user_cfg->getType() != Element::string) {
}
}
+HttpResponseJsonPtr
+BasicHttpAuthConfig::checkAuth(const HttpResponseCreator& creator,
+ const ConstHttpRequestPtr& request) const {
+ const BasicHttpAuthMap& credentials = getCredentialMap();
+ bool authentic = false;
+ if (credentials.empty()) {
+ authentic = true;
+ } else try {
+ string value = request->getHeaderValue("Authorization");
+ // Trim space characters.
+ value = str::trim(value);
+ if (value.size() < 8) {
+ isc_throw(BadValue, "header content is too short");
+ }
+ // Get the authentication scheme which must be "basic".
+ string scheme = value.substr(0, 5);
+ str::lowercase(scheme);
+ if (scheme != "basic") {
+ isc_throw(BadValue, "not basic authentication");
+ }
+ // Skip the authentication scheme name and space characters.
+ value = value.substr(5);
+ value = str::trim(value);
+ // Verify the credential is in the list.
+ const auto it = credentials.find(value);
+ if (it != credentials.end()) {
+ LOG_DEBUG(http_logger, isc::log::DBGLVL_TRACE_BASIC,
+ HTTP_CLIENT_REQUEST_AUTHORIZED)
+ .arg(it->second);
+ authentic = true;
+ } else {
+ LOG_INFO(http_logger, HTTP_CLIENT_REQUEST_NOT_AUTHORIZED);
+ authentic = false;
+ }
+ } catch (const HttpMessageNonExistingHeader&) {
+ LOG_INFO(http_logger, HTTP_CLIENT_REQUEST_NO_AUTH_HEADER);
+ } catch (const BadValue& ex) {
+ LOG_INFO(http_logger, HTTP_CLIENT_REQUEST_BAD_AUTH_HEADER)
+ .arg(ex.what());
+ }
+ if (authentic) {
+ return (HttpResponseJsonPtr());
+ }
+ const string& realm = getRealm();
+ const string& scheme = "Basic";
+ HttpResponsePtr response =
+ creator.createStockHttpResponse(request, HttpStatusCode::UNAUTHORIZED);
+ response->reset();
+ response->context()->headers_.push_back(
+ HttpHeaderContext("WWW-Authenticate",
+ scheme + " realm=\"" + realm + "\""));
+ response->finalize();
+ return (boost::dynamic_pointer_cast<HttpResponseJson>(response));
+}
+
} // end of namespace isc::http
} // end of namespace isc
#ifndef HTTP_BASIC_AUTH_CONFIG_H
#define HTTP_BASIC_AUTH_CONFIG_H
-#include <cc/cfg_to_element.h>
-#include <cc/data.h>
-#include <cc/simple_parser.h>
-#include <cc/user_context.h>
+#include <http/auth_config.h>
#include <http/basic_auth.h>
#include <list>
#include <unordered_map>
typedef std::list<BasicHttpAuthClient> BasicHttpAuthClientList;
/// @brief Basic HTTP authentication configuration.
-class BasicHttpAuthConfig : public isc::data::CfgToElement {
+class BasicHttpAuthConfig : public HttpAuthConfig {
public:
+ /// @brief Destructor.
+ virtual ~BasicHttpAuthConfig() { }
+
/// @brief Add a client configuration.
///
/// @param user User id
const std::string& password,
const isc::data::ConstElementPtr& user_context = isc::data::ConstElementPtr());
+ /// @brief Empty predicate.
+ /// @return true if the configuration is empty so authentication
+ /// is not required.
+ virtual bool empty() const;
+
/// @brief Clear configuration.
- void clear();
+ virtual void clear();
/// @brief Returns the list of client configuration.
///
/// @return A pointer to unparsed basic HTTP authentication configuration.
virtual isc::data::ElementPtr toElement() const;
+ /// @brief Validate HTTP request.
+ ///
+ /// @param creator The HTTP response creator.
+ /// @param request The HTTP request to validate.
+ /// @return Error HTTP response if validation failed, null otherwise.
+ virtual isc::http::HttpResponseJsonPtr
+ checkAuth(const isc::http::HttpResponseCreator& creator,
+ const isc::http::ConstHttpRequestPtr& request) const;
+
private:
/// @brief The list of basic HTTP authentication client configuration.
BasicHttpAuthMap map_;
};
+/// @brief Type of shared pointers to basic HTTP authentication configuration.
+typedef boost::shared_ptr<BasicHttpAuthConfig> BasicHttpAuthConfigPtr;
+
} // end of namespace isc::http
} // end of namespace isc
+++ /dev/null
-// Copyright (C) 2020 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <http/http_log.h>
-#include <http/response_creator_auth.h>
-#include <util/strutil.h>
-
-using namespace isc;
-using namespace isc::util;
-using namespace std;
-
-namespace isc {
-namespace http {
-
-HttpResponseJsonPtr checkAuth(const HttpResponseCreator& creator,
- const ConstHttpRequestPtr& request,
- const BasicHttpAuthMap& credentials,
- const std::string& realm) {
- bool authentic = false;
- if (credentials.empty()) {
- authentic = true;
- } else try {
- string value = request->getHeaderValue("Authorization");
- // Trim space characters.
- value = str::trim(value);
- if (value.size() < 8) {
- isc_throw(BadValue, "header content is too short");
- }
- // Get the authentication scheme which must be "basic".
- string scheme = value.substr(0, 5);
- str::lowercase(scheme);
- if (scheme != "basic") {
- isc_throw(BadValue, "not basic authentication");
- }
- // Skip the authentication scheme name and space characters.
- value = value.substr(5);
- value = str::trim(value);
- // Verify the credential is in the list.
- const auto it = credentials.find(value);
- if (it != credentials.end()) {
- LOG_DEBUG(http_logger, isc::log::DBGLVL_TRACE_BASIC,
- HTTP_CLIENT_REQUEST_AUTHORIZED)
- .arg(it->second);
- authentic = true;
- } else {
- LOG_INFO(http_logger, HTTP_CLIENT_REQUEST_NOT_AUTHORIZED);
- authentic = false;
- }
- } catch (const HttpMessageNonExistingHeader&) {
- LOG_INFO(http_logger, HTTP_CLIENT_REQUEST_NO_AUTH_HEADER);
- } catch (const BadValue& ex) {
- LOG_INFO(http_logger, HTTP_CLIENT_REQUEST_BAD_AUTH_HEADER)
- .arg(ex.what());
- }
- if (authentic) {
- return (HttpResponseJsonPtr());
- }
- string scheme = "Basic";
- HttpResponsePtr response =
- creator.createStockHttpResponse(request, HttpStatusCode::UNAUTHORIZED);
- response->reset();
- response->context()->headers_.push_back(
- HttpHeaderContext("WWW-Authenticate",
- scheme + " realm=\"" + realm + "\""));
- response->finalize();
- return (boost::dynamic_pointer_cast<HttpResponseJson>(response));
-}
-
-} // end of namespace isc::http
-} // end of namespace isc
+++ /dev/null
-// Copyright (C) 2020 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef HTTP_RESPONSE_CREATOR_AUTH_H
-#define HTTP_RESPONSE_CREATOR_AUTH_H
-
-#include <http/basic_auth_config.h>
-#include <http/response_creator.h>
-#include <http/response_json.h>
-#include <string.h>
-#include <unordered_map>
-
-namespace isc {
-namespace http {
-
-/// @brief Validate authentication.
-///
-/// Currently it only validates basic HTTP authentication.
-/// Empty credentials map means that basic HTTP authentication is
-/// not required i.e. all requests validate.
-///
-/// @param creator The HTTP response creator.
-/// @param request The HTTP request to validate.
-/// @param credentials A map of all allowed credentials.
-/// @param realm Realm name.
-/// @return Error HTTP response if validation failed, null otherwise.
-HttpResponseJsonPtr checkAuth(const HttpResponseCreator& creator,
- const ConstHttpRequestPtr& request,
- const BasicHttpAuthMap& credentials,
- const std::string& realm);
-
-} // end of namespace isc::http
-} // end of namespace isc
-
-#endif // endif HTTP_RESPONSE_CREATOR_AUTH_H
BasicHttpAuthConfig config;
// Initial configuration is empty.
+ EXPECT_TRUE(config.empty());
+ EXPECT_TRUE(config.getRealm().empty());
EXPECT_TRUE(config.getClientList().empty());
EXPECT_TRUE(config.getCredentialMap().empty());
+ // Set the realm and user context.
+ EXPECT_NO_THROW(config.setRealm("my-realm"));
+ EXPECT_EQ("my-realm", config.getRealm());
+ ConstElementPtr horse = Element::fromJSON("{ \"value\": \"a horse\" }");
+ EXPECT_NO_THROW(config.setContext(horse));
+ EXPECT_TRUE(horse->equals(*config.getContext()));
+
// Add rejects user id with embedded ':'.
EXPECT_THROW(config.add("foo:", "bar"), BadValue);
// Add a client.
+ EXPECT_TRUE(config.empty());
ConstElementPtr ctx = Element::fromJSON("{ \"foo\": \"bar\" }");
EXPECT_NO_THROW(config.add("foo", "bar", ctx));
+ EXPECT_FALSE(config.empty());
// Check the client.
ASSERT_EQ(1, config.getClientList().size());
EXPECT_EQ("foo", user);
// Check toElement.
- ElementPtr expected = Element::createList();
+ ElementPtr expected = Element::createMap();
+ ElementPtr clients = Element::createList();
ElementPtr elem = Element::createMap();
elem->set("user", Element::create(string("foo")));
elem->set("password", Element::create(string("bar")));
elem->set("user-context", ctx);
- expected->add(elem);
+ clients->add(elem);
+ expected->set("type", Element::create(string("basic")));
+ expected->set("realm", Element::create(string("my-realm")));
+ expected->set("user-context", horse);
+ expected->set("clients", clients);
runToElementTest<BasicHttpAuthConfig>(expected, config);
// Add a second client and test it.
// Check clear.
config.clear();
- expected = Element::createList();
+ EXPECT_TRUE(config.empty());
+ expected->set("clients", Element::createList());
runToElementTest<BasicHttpAuthConfig>(expected, config);
// Add clients again.
ElementPtr elem0 = Element::createMap();
elem0->set("user", Element::create(string("test")));
elem0->set("password", Element::create(string("123\xa3")));
- expected->add(elem0);
- expected->add(elem);
+ clients = Element::createList();
+ clients->add(elem0);
+ clients->add(elem);
+ expected->set("clients", clients);
runToElementTest<BasicHttpAuthConfig>(expected, config);
}
// No config is accepted.
EXPECT_NO_THROW(config.parse(cfg));
+ EXPECT_TRUE(config.empty());
EXPECT_TRUE(config.getClientList().empty());
EXPECT_TRUE(config.getCredentialMap().empty());
- runToElementTest<BasicHttpAuthConfig>(Element::createList(), config);
+ ElementPtr expected = Element::createMap();
+ expected->set("type", Element::create(string("basic")));
+ expected->set("realm", Element::create(string("")));
+ expected->set("clients", Element::createList());
+ runToElementTest<BasicHttpAuthConfig>(expected, config);
- // The config must be a list.
+ // The config must be a map.
+ cfg = Element::createList();
+ EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
+ "authentication must be a map (:0:0)");
+
+ // The type must be present.
cfg = Element::createMap();
EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
- "basic-authentications must be a list (:0:0)");
+ "type is required in authentication (:0:0)");
+
+ // The type must be a string.
+ cfg->set("type", Element::create(true));
+ EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
+ "type is must be a string (:0:0)");
+
+ // The type must be basic.
+ cfg->set("type", Element::create(string("foobar")));
+ string errmsg = "only basic HTTP authentication is supported: type is ";
+ errmsg += "'foobar' not 'basic' (:0:0)";
+ EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError, errmsg);
+ cfg->set("type", Element::create(string("basic")));
+ EXPECT_NO_THROW(config.parse(cfg));
+
+ // The realm must be a string.
+ cfg->set("realm", Element::createList());
+ EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
+ "realm is must be a string (:0:0)");
+ cfg->set("realm", Element::create(string("my-realm")));
+ EXPECT_NO_THROW(config.parse(cfg));
+
+ // The user context must be a map.
+ ElementPtr ctx = Element::createList();
+ cfg->set("user-context", ctx);
+ EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
+ "user-context must be a map (:0:0)");
+ ctx = Element::fromJSON("{ \"value\": \"a horse\" }");
+ cfg->set("user-context", ctx);
+ EXPECT_NO_THROW(config.parse(cfg));
+
+ // Clients must be a list.
+ ElementPtr clients_cfg = Element::createMap();
+ cfg->set("clients", clients_cfg);
+ EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
+ "clients must be a list (:0:0)");
// The client config must be a map.
- cfg = Element::createList();
+ clients_cfg = Element::createList();
ElementPtr client_cfg = Element::createList();
- cfg->add(client_cfg);
+ clients_cfg->add(client_cfg);
+ cfg->set("clients", clients_cfg);
EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
- "basic-authentications items must be maps (:0:0)");
+ "clients items must be maps (:0:0)");
// The user parameter is mandatory in client config.
client_cfg = Element::createMap();
- cfg = Element::createList();
- cfg->add(client_cfg);
+ clients_cfg = Element::createList();
+ clients_cfg->add(client_cfg);
+ cfg->set("clients", clients_cfg);
EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
- "user is required in basic-authentications items (:0:0)");
+ "user is required in clients items (:0:0)");
// The user parameter must be a string.
ElementPtr user_cfg = Element::create(1);
client_cfg = Element::createMap();
client_cfg->set("user", user_cfg);
- cfg = Element::createList();
- cfg->add(client_cfg);
+ clients_cfg = Element::createList();
+ clients_cfg->add(client_cfg);
+ cfg->set("clients", clients_cfg);
EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
"user must be a string (:0:0)");
user_cfg = Element::create(string(""));
client_cfg = Element::createMap();
client_cfg->set("user", user_cfg);
- cfg = Element::createList();
- cfg->add(client_cfg);
+ clients_cfg = Element::createList();
+ clients_cfg->add(client_cfg);
+ cfg->set("clients", clients_cfg);
EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
"user must be not be empty (:0:0)");
user_cfg = Element::create(string("foo:bar"));
client_cfg = Element::createMap();
client_cfg->set("user", user_cfg);
- cfg = Element::createList();
- cfg->add(client_cfg);
+ clients_cfg = Element::createList();
+ clients_cfg->add(client_cfg);
+ cfg->set("clients", clients_cfg);
EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
"user must not contain a ':': 'foo:bar' (:0:0)");
user_cfg = Element::create(string("foo"));
client_cfg = Element::createMap();
client_cfg->set("user", user_cfg);
- cfg = Element::createList();
- cfg->add(client_cfg);
+ clients_cfg = Element::createList();
+ clients_cfg->add(client_cfg);
+ cfg->set("clients", clients_cfg);
EXPECT_NO_THROW(config.parse(cfg));
ASSERT_EQ(1, config.getClientList().size());
EXPECT_EQ("", config.getClientList().front().getPassword());
client_cfg = Element::createMap();
client_cfg->set("user", user_cfg);
client_cfg->set("password", password_cfg);
- cfg = Element::createList();
- cfg->add(client_cfg);
+ clients_cfg = Element::createList();
+ clients_cfg->add(client_cfg);
+ cfg->set("clients", clients_cfg);
EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
"password must be a string (:0:0)");
client_cfg = Element::createMap();
client_cfg->set("user", user_cfg);
client_cfg->set("password", password_cfg);
- cfg = Element::createList();
- cfg->add(client_cfg);
+ clients_cfg = Element::createList();
+ clients_cfg->add(client_cfg);
+ cfg->set("clients", clients_cfg);
EXPECT_NO_THROW(config.parse(cfg));
ASSERT_EQ(1, config.getClientList().size());
EXPECT_EQ("", config.getClientList().front().getPassword());
// User context must be a map.
password_cfg = Element::create(string("bar"));
- ElementPtr ctx = Element::createList();
+ ctx = Element::createList();
client_cfg = Element::createMap();
client_cfg->set("user", user_cfg);
client_cfg->set("password", password_cfg);
client_cfg->set("user-context", ctx);
- cfg = Element::createList();
- cfg->add(client_cfg);
+ clients_cfg = Element::createList();
+ clients_cfg->add(client_cfg);
+ cfg->set("clients", clients_cfg);
EXPECT_THROW_MSG(config.parse(cfg), DhcpConfigError,
"user-context must be a map (:0:0)");
client_cfg->set("user", user_cfg);
client_cfg->set("password", password_cfg);
client_cfg->set("user-context", ctx);
- cfg = Element::createList();
- cfg->add(client_cfg);
+ clients_cfg = Element::createList();
+ clients_cfg->add(client_cfg);
+ cfg->set("clients", clients_cfg);
EXPECT_NO_THROW(config.parse(cfg));
runToElementTest<BasicHttpAuthConfig>(cfg, config);
}
#include <config.h>
#include <http/basic_auth.h>
+#include <http/basic_auth_config.h>
#include <http/http_types.h>
#include <http/request.h>
#include <http/response.h>
#include <http/response_creator.h>
-#include <http/response_creator_auth.h>
#include <http/response_json.h>
#include <http/tests/response_test.h>
#include <testutils/log_utils.h>
// This test verifies that missing required authentication header gives
// unauthorized error.
TEST_F(HttpResponseCreatorAuthTest, noAuth) {
- // Create credentials.
- BasicHttpAuthPtr basic_auth;
- EXPECT_NO_THROW(basic_auth.reset(new BasicHttpAuth("test", "123\xa3")));
- EXPECT_EQ("dGVzdDoxMjPCow==", basic_auth->getCredential());
- BasicHttpAuthMap credentials;
- credentials[basic_auth->getCredential()] = "test";
- string realm = "ISC.ORG";
+ // Create basic HTTP authentication configuration.
+ BasicHttpAuthConfigPtr auth_config(new BasicHttpAuthConfig());
+ EXPECT_NO_THROW(auth_config->add("test", "123\xa3"));
+ const BasicHttpAuthMap& credentials = auth_config->getCredentialMap();
+ auto cred = credentials.find("dGVzdDoxMjPCow==");
+ EXPECT_NE(cred, credentials.end());
+ EXPECT_EQ(cred->second, "test");
+ auth_config->setRealm("ISC.ORG");
// Create request and finalize it.
HttpRequestPtr request(new HttpRequest());
HttpResponsePtr response;
TestHttpResponseCreatorPtr creator(new TestHttpResponseCreator());;
- ASSERT_NO_THROW(response = checkAuth(*creator, request, credentials, realm));
+ ASSERT_NO_THROW(response = auth_config->checkAuth(*creator, request));
ASSERT_TRUE(response);
EXPECT_EQ("HTTP/1.0 401 Unauthorized\r\n"
// This test verifies that too short authentication header is rejected.
TEST_F(HttpResponseCreatorAuthTest, authTooShort) {
- // Create credentials.
- BasicHttpAuthPtr basic_auth;
- EXPECT_NO_THROW(basic_auth.reset(new BasicHttpAuth("test", "123\xa3")));
- EXPECT_EQ("dGVzdDoxMjPCow==", basic_auth->getCredential());
- BasicHttpAuthMap credentials;
- credentials[basic_auth->getCredential()] = "test";
- string realm = "ISC.ORG";
+ // Create basic HTTP authentication configuration.
+ BasicHttpAuthConfigPtr auth_config(new BasicHttpAuthConfig());
+ EXPECT_NO_THROW(auth_config->add("test", "123\xa3"));
+ const BasicHttpAuthMap& credentials = auth_config->getCredentialMap();
+ auto cred = credentials.find("dGVzdDoxMjPCow==");
+ EXPECT_NE(cred, credentials.end());
+ EXPECT_EQ(cred->second, "test");
+ auth_config->setRealm("ISC.ORG");
// Create request and finalize it.
HttpRequestPtr request(new HttpRequest());
HttpResponsePtr response;
TestHttpResponseCreatorPtr creator(new TestHttpResponseCreator());;
- ASSERT_NO_THROW(response = checkAuth(*creator, request, credentials, realm));
+ ASSERT_NO_THROW(response = auth_config->checkAuth(*creator, request));
ASSERT_TRUE(response);
EXPECT_EQ("HTTP/1.0 401 Unauthorized\r\n"
// This test verifies that another authentication schema is rejected.
TEST_F(HttpResponseCreatorAuthTest, badScheme) {
- // Create credentials.
- BasicHttpAuthPtr basic_auth;
- EXPECT_NO_THROW(basic_auth.reset(new BasicHttpAuth("test", "123\xa3")));
- EXPECT_EQ("dGVzdDoxMjPCow==", basic_auth->getCredential());
- BasicHttpAuthMap credentials;
- credentials[basic_auth->getCredential()] = "test";
- string realm = "ISC.ORG";
+ // Create basic HTTP authentication configuration.
+ BasicHttpAuthConfigPtr auth_config(new BasicHttpAuthConfig());
+ EXPECT_NO_THROW(auth_config->add("test", "123\xa3"));
+ const BasicHttpAuthMap& credentials = auth_config->getCredentialMap();
+ auto cred = credentials.find("dGVzdDoxMjPCow==");
+ EXPECT_NE(cred, credentials.end());
+ EXPECT_EQ(cred->second, "test");
+ auth_config->setRealm("ISC.ORG");
// Create request and finalize it.
HttpRequestPtr request(new HttpRequest());
HttpResponsePtr response;
TestHttpResponseCreatorPtr creator(new TestHttpResponseCreator());;
- ASSERT_NO_THROW(response = checkAuth(*creator, request, credentials, realm));
+ ASSERT_NO_THROW(response = auth_config->checkAuth(*creator, request));
ASSERT_TRUE(response);
EXPECT_EQ("HTTP/1.0 401 Unauthorized\r\n"
// This test verifies that not matching credential is rejected.
TEST_F(HttpResponseCreatorAuthTest, notMatching) {
- // Create credentials.
- BasicHttpAuthPtr basic_auth;
- EXPECT_NO_THROW(basic_auth.reset(new BasicHttpAuth("test", "123\xa3")));
- EXPECT_EQ("dGVzdDoxMjPCow==", basic_auth->getCredential());
- BasicHttpAuthMap credentials;
- credentials[basic_auth->getCredential()] = "test";
- string realm = "ISC.ORG";
+ // Create basic HTTP authentication configuration.
+ BasicHttpAuthConfigPtr auth_config(new BasicHttpAuthConfig());
+ EXPECT_NO_THROW(auth_config->add("test", "123\xa3"));
+ const BasicHttpAuthMap& credentials = auth_config->getCredentialMap();
+ auto cred = credentials.find("dGVzdDoxMjPCow==");
+ EXPECT_NE(cred, credentials.end());
+ EXPECT_EQ(cred->second, "test");
+ auth_config->setRealm("ISC.ORG");
// Create request and finalize it.
HttpRequestPtr request(new HttpRequest());
HttpResponsePtr response;
TestHttpResponseCreatorPtr creator(new TestHttpResponseCreator());;
- ASSERT_NO_THROW(response = checkAuth(*creator, request, credentials, realm));
+ ASSERT_NO_THROW(response = auth_config->checkAuth(*creator, request));
ASSERT_TRUE(response);
EXPECT_EQ("HTTP/1.0 401 Unauthorized\r\n"
// This test verifies that matching credential is accepted.
TEST_F(HttpResponseCreatorAuthTest, matching) {
- // Create credentials.
- BasicHttpAuthPtr basic_auth;
- EXPECT_NO_THROW(basic_auth.reset(new BasicHttpAuth("test", "123\xa3")));
- EXPECT_EQ("dGVzdDoxMjPCow==", basic_auth->getCredential());
- BasicHttpAuthMap credentials;
- credentials[basic_auth->getCredential()] = "test";
- string realm = "ISC.ORG";
+ // Create basic HTTP authentication configuration.
+ BasicHttpAuthConfigPtr auth_config(new BasicHttpAuthConfig());
+ EXPECT_NO_THROW(auth_config->add("test", "123\xa3"));
+ const BasicHttpAuthMap& credentials = auth_config->getCredentialMap();
+ auto cred = credentials.find("dGVzdDoxMjPCow==");
+ EXPECT_NE(cred, credentials.end());
+ EXPECT_EQ(cred->second, "test");
+ auth_config->setRealm("ISC.ORG");
// Create request and finalize it.
HttpRequestPtr request(new HttpRequest());
request->context()->http_version_minor_ = 0;
request->context()->method_ = "GET";
request->context()->uri_ = "/foo";
- BasicAuthHttpHeaderContext auth(*basic_auth);
+ HttpHeaderContext auth("Authorization", "Basic dGVzdDoxMjPCow==");
request->context()->headers_.push_back(auth);
ASSERT_NO_THROW(request->finalize());
HttpResponsePtr response;
TestHttpResponseCreatorPtr creator(new TestHttpResponseCreator());;
- ASSERT_NO_THROW(response = checkAuth(*creator, request, credentials, realm));
+ ASSERT_NO_THROW(response = auth_config->checkAuth(*creator, request));
EXPECT_FALSE(response);
addString("HTTP_CLIENT_REQUEST_AUTHORIZED received HTTP request "