]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1304] Prepared server callout
authorFrancis Dupont <fdupont@isc.org>
Tue, 28 Jul 2020 14:26:42 +0000 (16:26 +0200)
committerFrancis Dupont <fdupont@isc.org>
Sat, 12 Sep 2020 08:50:34 +0000 (10:50 +0200)
src/bin/agent/ca_response_creator.cc
src/lib/http/response_creator_auth.cc
src/lib/http/response_creator_auth.h
src/lib/http/tests/response_creator_unittests.cc

index c102157f21d97b9182cdb9c2d25d0d2f8f7a6859..75fb93b6cd1b65d67593ae03a7d647631bdbda77 100644 (file)
@@ -83,12 +83,9 @@ createDynamicHttpResponse(const ConstHttpRequestPtr& request) {
                 if (ctx) {
                     const BasicHttpAuthConfig& auth = ctx->getBasicAuthConfig();
                     const BasicHttpAuthMap& auth_map = auth.getCredentialMap();
-                    // Check authentication when required.
-                    if (!auth_map.empty()) {
-                        http_response =
-                            checkBasicHttpAuth(*this, request, auth_map,
-                                               ctx->getBasicAuthRealm());
-                    }
+                    // Check authentication.
+                    http_response = checkAuth(*this, request, auth_map,
+                                              ctx->getBasicAuthRealm());
                 }
             }
         }
index 3b278ddb046ad449492a4b72be61c9bf1e9a108f..4a19c14008bf90a18b216e041d9716244ea6b7eb 100644 (file)
@@ -17,11 +17,14 @@ using namespace std;
 namespace isc {
 namespace http {
 
-HttpResponseJsonPtr checkBasicHttpAuth(const HttpResponseCreator& creator,
-                                       const ConstHttpRequestPtr& request,
-                                       const BasicHttpAuthMap& credentials,
-                                       const std::string& realm) {
-    try {
+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);
@@ -43,21 +46,27 @@ HttpResponseJsonPtr checkBasicHttpAuth(const HttpResponseCreator& creator,
             LOG_DEBUG(http_logger, isc::log::DBGLVL_TRACE_BASIC,
                       HTTP_CLIENT_REQUEST_AUTHORIZED)
                 .arg(it->second);
-            return (HttpResponseJsonPtr());
+            authentic = true;
+        } else {
+            LOG_INFO(http_logger, HTTP_CLIENT_REQUEST_NOT_AUTHORIZED);
+            authentic = false;
         }
-        LOG_INFO(http_logger, HTTP_CLIENT_REQUEST_NOT_AUTHORIZED);
     } 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",
-                          "Basic realm=\"" + realm + "\""));
+                          scheme + " realm=\"" + realm + "\""));
     response->finalize();
     return (boost::dynamic_pointer_cast<HttpResponseJson>(response));
 }
index 830b335f6bbe0b25534ae21969e82a10283cf23d..26e1c1aca312120b66117f3154fda638dcb61c02 100644 (file)
 namespace isc {
 namespace http {
 
-/// @brief Validate basic HTTP authentication.
+/// @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 checkBasicHttpAuth(const HttpResponseCreator& creator,
-                                       const ConstHttpRequestPtr& request,
-                                       const BasicHttpAuthMap& credentials,
-                                       const std::string& realm);
+HttpResponseJsonPtr checkAuth(const HttpResponseCreator& creator,
+                              const ConstHttpRequestPtr& request,
+                              const BasicHttpAuthMap& credentials,
+                              const std::string& realm);
 
 } // end of namespace isc::http
 } // end of namespace isc
index e32f60dcbdb1c2dbea01801a48ddbef39ebe3f38..35836c22eb7cde8ae7c6bcf79beb14bf31aa6aa9 100644 (file)
@@ -109,6 +109,9 @@ TEST(HttpResponseCreatorTest, badRequest) {
 // This test verifies that response is generated successfully from the
 // finalized/parsed request.
 TEST(HttpResponseCreatorTest, goodRequest) {
+    // There is no credentials so it checks also what happens when
+    // authentication is not required.
+
     HttpResponsePtr response;
     // Create request and finalize it.
     HttpRequestPtr request(new HttpRequest());
@@ -137,6 +140,14 @@ class HttpResponseCreatorAuthTest : public LogContentTest { };
 // 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 request and finalize it.
     HttpRequestPtr request(new HttpRequest());
     request->context()->http_version_major_ = 1;
@@ -147,11 +158,7 @@ TEST_F(HttpResponseCreatorAuthTest, noAuth) {
 
     HttpResponsePtr response;
     TestHttpResponseCreatorPtr creator(new TestHttpResponseCreator());;
-    BasicHttpAuthMap credentials;
-    string realm = "ISC.ORG";
-
-    ASSERT_NO_THROW(response =
-        checkBasicHttpAuth(*creator, request, credentials, realm));
+    ASSERT_NO_THROW(response = checkAuth(*creator, request, credentials, realm));
     ASSERT_TRUE(response);
 
     EXPECT_EQ("HTTP/1.0 401 Unauthorized\r\n"
@@ -169,6 +176,14 @@ TEST_F(HttpResponseCreatorAuthTest, noAuth) {
 
 // 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 request and finalize it.
     HttpRequestPtr request(new HttpRequest());
     request->context()->http_version_major_ = 1;
@@ -181,11 +196,7 @@ TEST_F(HttpResponseCreatorAuthTest, authTooShort) {
 
     HttpResponsePtr response;
     TestHttpResponseCreatorPtr creator(new TestHttpResponseCreator());;
-    BasicHttpAuthMap credentials;
-    string realm = "ISC.ORG";
-
-    ASSERT_NO_THROW(response =
-        checkBasicHttpAuth(*creator, request, credentials, realm));
+    ASSERT_NO_THROW(response = checkAuth(*creator, request, credentials, realm));
     ASSERT_TRUE(response);
 
     EXPECT_EQ("HTTP/1.0 401 Unauthorized\r\n"
@@ -204,6 +215,14 @@ TEST_F(HttpResponseCreatorAuthTest, authTooShort) {
 
 // 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 request and finalize it.
     HttpRequestPtr request(new HttpRequest());
     request->context()->http_version_major_ = 1;
@@ -216,11 +235,7 @@ TEST_F(HttpResponseCreatorAuthTest, badScheme) {
 
     HttpResponsePtr response;
     TestHttpResponseCreatorPtr creator(new TestHttpResponseCreator());;
-    BasicHttpAuthMap credentials;
-    string realm = "ISC.ORG";
-
-    ASSERT_NO_THROW(response =
-        checkBasicHttpAuth(*creator, request, credentials, realm));
+    ASSERT_NO_THROW(response = checkAuth(*creator, request, credentials, realm));
     ASSERT_TRUE(response);
 
     EXPECT_EQ("HTTP/1.0 401 Unauthorized\r\n"
@@ -239,23 +254,28 @@ TEST_F(HttpResponseCreatorAuthTest, badScheme) {
 
 // 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 request and finalize it.
     HttpRequestPtr request(new HttpRequest());
     request->context()->http_version_major_ = 1;
     request->context()->http_version_minor_ = 0;
     request->context()->method_ = "GET";
     request->context()->uri_ = "/foo";
-    HttpHeaderContext auth("Authorization", "Basic dGVzdDoxMjPCow==");
+    // Slightly different credential...
+    HttpHeaderContext auth("Authorization", "Basic dGvZdDoxMjPcOw==");
     request->context()->headers_.push_back(auth);
     ASSERT_NO_THROW(request->finalize());
 
     HttpResponsePtr response;
     TestHttpResponseCreatorPtr creator(new TestHttpResponseCreator());;
-    BasicHttpAuthMap credentials;
-    string realm = "ISC.ORG";
-
-    ASSERT_NO_THROW(response =
-        checkBasicHttpAuth(*creator, request, credentials, realm));
+    ASSERT_NO_THROW(response = checkAuth(*creator, request, credentials, realm));
     ASSERT_TRUE(response);
 
     EXPECT_EQ("HTTP/1.0 401 Unauthorized\r\n"
@@ -273,27 +293,27 @@ TEST_F(HttpResponseCreatorAuthTest, notMatching) {
 
 // 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 request and finalize it.
     HttpRequestPtr request(new HttpRequest());
     request->context()->http_version_major_ = 1;
     request->context()->http_version_minor_ = 0;
     request->context()->method_ = "GET";
     request->context()->uri_ = "/foo";
-    BasicHttpAuthPtr basic_auth;
-    EXPECT_NO_THROW(basic_auth.reset(new BasicHttpAuth("test", "123\xa3")));
-    EXPECT_EQ("dGVzdDoxMjPCow==", basic_auth->getCredential());
     BasicAuthHttpHeaderContext auth(*basic_auth);
     request->context()->headers_.push_back(auth);
     ASSERT_NO_THROW(request->finalize());
 
     HttpResponsePtr response;
     TestHttpResponseCreatorPtr creator(new TestHttpResponseCreator());;
-    BasicHttpAuthMap credentials;
-    credentials[basic_auth->getCredential()] = "test";
-    string realm = "ISC.ORG";
-
-    ASSERT_NO_THROW(response =
-        checkBasicHttpAuth(*creator, request, credentials, realm));
+    ASSERT_NO_THROW(response = checkAuth(*creator, request, credentials, realm));
     EXPECT_FALSE(response);
 
     addString("HTTP_CLIENT_REQUEST_AUTHORIZED received HTTP request "