diff options
author | Roland Reichwein <mail@reichwein.it> | 2020-05-29 11:31:40 +0200 |
---|---|---|
committer | Roland Reichwein <mail@reichwein.it> | 2020-05-29 11:31:40 +0200 |
commit | e0451ef59a69eda29efa6bc22294b2bcf8b8b600 (patch) | |
tree | dc80766930ca36ef5394b648b3658d41c1cd0abc | |
parent | f1f4cbd996aa00b6e4d3d04d0223d02fd553dd96 (diff) |
Authentication infrastructure
-rw-r--r-- | debian/changelog | 8 | ||||
-rw-r--r-- | plugin_interface.h | 3 | ||||
-rw-r--r-- | plugins/cgi/cgi.cpp | 4 | ||||
-rw-r--r-- | plugins/cgi/cgi.h | 6 | ||||
-rw-r--r-- | plugins/fcgi/fcgi.cpp | 5 | ||||
-rw-r--r-- | plugins/fcgi/fcgi.h | 6 | ||||
-rw-r--r-- | plugins/redirect/redirect.cpp | 5 | ||||
-rw-r--r-- | plugins/redirect/redirect.h | 7 | ||||
-rw-r--r-- | plugins/static-files/static-files.cpp | 5 | ||||
-rw-r--r-- | plugins/static-files/static-files.h | 5 | ||||
-rw-r--r-- | plugins/statistics/statistics.cpp | 5 | ||||
-rw-r--r-- | plugins/statistics/statistics.h | 5 | ||||
-rw-r--r-- | plugins/webbox/webbox.cpp | 4 | ||||
-rw-r--r-- | plugins/webbox/webbox.h | 8 | ||||
-rw-r--r-- | plugins/weblog/weblog.cpp | 4 | ||||
-rw-r--r-- | plugins/weblog/weblog.h | 6 | ||||
-rw-r--r-- | response.cpp | 81 |
17 files changed, 122 insertions, 45 deletions
diff --git a/debian/changelog b/debian/changelog index 23a6097..eb9a600 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +webserver (1.8) unstable; urgency=medium + + * Automatically reopen broken fcgi sockets + * Fix empty fcgi stderr messages + * Authorization: Default HTTP AUTH, except for webbox with own login page + + -- Roland Reichwein <rr@antcom.de> Fri, 29 May 2020 10:23:06 +0200 + webserver (1.7) unstable; urgency=medium * Omit PEM file reload. Access to files is denied because of dropped privileges. diff --git a/plugin_interface.h b/plugin_interface.h index c0a95b9..830c44c 100644 --- a/plugin_interface.h +++ b/plugin_interface.h @@ -27,6 +27,9 @@ public: std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader // to be added to result string ) = 0; + // Plugin provides own authentication mechanism? Otherwise, webserver makes HTTP AUTH via status 401 + virtual bool has_own_authentication() = 0; + virtual ~webserver_plugin_interface(){} // optional }; diff --git a/plugins/cgi/cgi.cpp b/plugins/cgi/cgi.cpp index 480ae9e..131855e 100644 --- a/plugins/cgi/cgi.cpp +++ b/plugins/cgi/cgi.cpp @@ -290,3 +290,7 @@ std::string cgi_plugin::generate_page( } } +bool cgi_plugin::has_own_authentication() +{ + return false; +} diff --git a/plugins/cgi/cgi.h b/plugins/cgi/cgi.h index 467a6c4..5093901 100644 --- a/plugins/cgi/cgi.h +++ b/plugins/cgi/cgi.h @@ -8,12 +8,14 @@ public: cgi_plugin(); ~cgi_plugin(); - std::string name(); + std::string name() override; std::string generate_page( std::function<std::string(const std::string& key)>& GetServerParam, std::function<std::string(const std::string& key)>& GetRequestParam, // request including body (POST...) std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader // to be added to result string - ); + ) override; + + bool has_own_authentication() override; }; diff --git a/plugins/fcgi/fcgi.cpp b/plugins/fcgi/fcgi.cpp index 6f4ad1f..22a4d40 100644 --- a/plugins/fcgi/fcgi.cpp +++ b/plugins/fcgi/fcgi.cpp @@ -538,3 +538,8 @@ std::string fcgi_plugin::generate_page( } } +bool fcgi_plugin::has_own_authentication() +{ + return false; +} + diff --git a/plugins/fcgi/fcgi.h b/plugins/fcgi/fcgi.h index 289c4d6..167a356 100644 --- a/plugins/fcgi/fcgi.h +++ b/plugins/fcgi/fcgi.h @@ -41,12 +41,14 @@ public: fcgi_plugin(); ~fcgi_plugin(); - std::string name(); + std::string name() override; std::string generate_page( std::function<std::string(const std::string& key)>& GetServerParam, std::function<std::string(const std::string& key)>& GetRequestParam, // request including body (POST...) std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader // to be added to result string - ); + ) override; + + bool has_own_authentication() override; std::string fcgiQuery(FCGIContext& context); }; diff --git a/plugins/redirect/redirect.cpp b/plugins/redirect/redirect.cpp index 91d5f64..796926d 100644 --- a/plugins/redirect/redirect.cpp +++ b/plugins/redirect/redirect.cpp @@ -62,3 +62,8 @@ std::string redirect_plugin::generate_page( } } +bool redirect_plugin::has_own_authentication() +{ + return false; +} + diff --git a/plugins/redirect/redirect.h b/plugins/redirect/redirect.h index 403cc16..472f9f2 100644 --- a/plugins/redirect/redirect.h +++ b/plugins/redirect/redirect.h @@ -8,13 +8,14 @@ public: redirect_plugin(); ~redirect_plugin(); - std::string name(); + std::string name() override; std::string generate_page( std::function<std::string(const std::string& key)>& GetServerParam, std::function<std::string(const std::string& key)>& GetRequestParam, // request including body (POST...) std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader // to be added to result string - ); - + ) override; + + bool has_own_authentication() override; }; extern "C" BOOST_SYMBOL_EXPORT redirect_plugin webserver_plugin; diff --git a/plugins/static-files/static-files.cpp b/plugins/static-files/static-files.cpp index 345cf56..b2dcdca 100644 --- a/plugins/static-files/static-files.cpp +++ b/plugins/static-files/static-files.cpp @@ -115,3 +115,8 @@ std::string static_files_plugin::generate_page( } } +bool static_files_plugin::has_own_authentication() +{ + return false; +} + diff --git a/plugins/static-files/static-files.h b/plugins/static-files/static-files.h index ff35e92..a119387 100644 --- a/plugins/static-files/static-files.h +++ b/plugins/static-files/static-files.h @@ -8,13 +8,14 @@ public: static_files_plugin(); ~static_files_plugin(); - std::string name(); + std::string name() override; std::string generate_page( std::function<std::string(const std::string& key)>& GetServerParam, std::function<std::string(const std::string& key)>& GetRequestParam, // request including body (POST...) std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader // to be added to result string - ); + ) override; + bool has_own_authentication() override; }; extern "C" BOOST_SYMBOL_EXPORT static_files_plugin webserver_plugin; diff --git a/plugins/statistics/statistics.cpp b/plugins/statistics/statistics.cpp index 6d3899e..3ebd301 100644 --- a/plugins/statistics/statistics.cpp +++ b/plugins/statistics/statistics.cpp @@ -132,3 +132,8 @@ std::string statistics_plugin::generate_page( } } +bool statistics_plugin::has_own_authentication() +{ + return false; +} + diff --git a/plugins/statistics/statistics.h b/plugins/statistics/statistics.h index 5db309b..e998643 100644 --- a/plugins/statistics/statistics.h +++ b/plugins/statistics/statistics.h @@ -8,13 +8,14 @@ public: statistics_plugin(); ~statistics_plugin(); - std::string name(); + std::string name() override; std::string generate_page( std::function<std::string(const std::string& key)>& GetServerParam, std::function<std::string(const std::string& key)>& GetRequestParam, // request including body (POST...) std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader // to be added to result string - ); + ) override; + bool has_own_authentication() override; }; extern "C" BOOST_SYMBOL_EXPORT statistics_plugin webserver_plugin; diff --git a/plugins/webbox/webbox.cpp b/plugins/webbox/webbox.cpp index 09ac7c5..de8df85 100644 --- a/plugins/webbox/webbox.cpp +++ b/plugins/webbox/webbox.cpp @@ -943,3 +943,7 @@ void webbox_plugin::registerCommand(std::shared_ptr<Command> command) m_commands[command->getCommandName()] = command; }; +bool webbox_plugin::has_own_authentication() +{ + return true; +} diff --git a/plugins/webbox/webbox.h b/plugins/webbox/webbox.h index dd2fb93..cd4e21d 100644 --- a/plugins/webbox/webbox.h +++ b/plugins/webbox/webbox.h @@ -18,12 +18,16 @@ private: public: webbox_plugin(); ~webbox_plugin(); - std::string name(); + + std::string name() override; + std::string generate_page( std::function<std::string(const std::string& key)>& GetServerParam, std::function<std::string(const std::string& key)>& GetRequestParam, // request including body (POST...) std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader // to be added to result string - ); + ) override; + + bool has_own_authentication() override; }; extern "C" BOOST_SYMBOL_EXPORT webbox_plugin webserver_plugin; diff --git a/plugins/weblog/weblog.cpp b/plugins/weblog/weblog.cpp index c18f120..1e1b6b2 100644 --- a/plugins/weblog/weblog.cpp +++ b/plugins/weblog/weblog.cpp @@ -441,3 +441,7 @@ std::string weblog_plugin::generate_page( } } +bool weblog_plugin::has_own_authentication() +{ + return false; +} diff --git a/plugins/weblog/weblog.h b/plugins/weblog/weblog.h index 28b4ab3..0994b91 100644 --- a/plugins/weblog/weblog.h +++ b/plugins/weblog/weblog.h @@ -8,13 +8,15 @@ public: weblog_plugin(); ~weblog_plugin(); - std::string name(); + std::string name() override; + std::string generate_page( std::function<std::string(const std::string& key)>& GetServerParam, std::function<std::string(const std::string& key)>& GetRequestParam, // request including body (POST...) std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader // to be added to result string - ); + ) override; + bool has_own_authentication() override; }; extern "C" BOOST_SYMBOL_EXPORT weblog_plugin webserver_plugin; diff --git a/response.cpp b/response.cpp index 5f4f3f2..9ee1977 100644 --- a/response.cpp +++ b/response.cpp @@ -69,7 +69,39 @@ public: Server& GetServer() const {return m_server; } const Socket& GetSocket() const {return m_server.GetSocket(); } -}; + + // Returns error message, empty on auth success + std::string isAuthenticated() + { + auto& auth{m_path.auth}; + if (auth.size() != 0) { + std::string authorization{m_req[http::field::authorization]}; + if (authorization.substr(0, 6) != "Basic "s) { + return "Bad Authorization Type"; + } + + authorization = authorization.substr(6); + authorization = decode64(authorization); + + size_t pos {authorization.find(':')}; + if (pos == authorization.npos) + return "Bad Authorization Encoding"; + + std::string login{authorization.substr(0, pos)}; + std::string password{authorization.substr(pos + 1)}; + + auto it {auth.find(login)}; + // it.second contains crypted/hash + // password is plain text to validate against the hash + if (it == auth.end() || !Auth::validate(it->second, password)) { + return "Bad Authorization"; + } + } + + return ""; + } + +}; // class RequestContext std::string extend_index_html(std::string path) { @@ -106,6 +138,8 @@ std::string GetServerParam(const std::string& key, Server& server) std::unordered_map<std::string, std::function<std::string(RequestContext&)>> GetRequestParamFunctions{ // following are the supported fields: {"authorization", [](RequestContext& req_ctx) { return std::string{req_ctx.GetReq()[http::field::authorization]}; }}, + + {"is_authenticated", [](RequestContext& req_ctx) { return req_ctx.isAuthenticated() == ""s ? "1"s : "0"s;}}, {"body", [](RequestContext& req_ctx) { return req_ctx.GetReq().body(); }}, @@ -232,6 +266,19 @@ response_type HttpStatusAndStats(std::string status, std::string message, Reques return std::move(res); } +response_type handleAuth(RequestContext& req_ctx, response_type& res) +{ + if (req_ctx.GetPlugin()->has_own_authentication() == false) { + std::string message { req_ctx.isAuthenticated() }; + if (message != "") { + res.set(http::field::www_authenticate, "Basic realm=\"Reichwein.IT Webserver Login\""); + return HttpStatusAndStats("401", message, req_ctx, res); + } + } + + return std::move(res); +} + } // anonymous namespace response_type generate_response(request_type& req, Server& server) @@ -244,35 +291,9 @@ response_type generate_response(request_type& req, Server& server) try { RequestContext req_ctx{req, server}; // can throw std::out_of_range - auto& auth{req_ctx.GetPath().auth}; - if (auth.size() != 0) { - std::string authorization{req[http::field::authorization]}; - if (authorization.substr(0, 6) != "Basic "s) - return HttpStatusAndStats("401", "Bad Authorization Type", req_ctx, res); - - authorization = authorization.substr(6); - authorization = decode64(authorization); - - size_t pos {authorization.find(':')}; - if (pos == authorization.npos) - return HttpStatusAndStats("401", "Bad Authorization Encoding", req_ctx, res); - - std::string login{authorization.substr(0, pos)}; - std::string password{authorization.substr(pos + 1)}; - - auto it {auth.find(login)}; - // it.second contains crypted/hash - // password is plain text to validate against the hash - if (it == auth.end() || !Auth::validate(it->second, password)) { - - // For now, WWW-Authenticate: Basic realm="..." will only be generated for static-files. - // All other plugins are expected to present their own login pages - if (req_ctx.GetPluginName() == "static-files") - res.set(http::field::www_authenticate, "Basic realm=\"Reichwein.IT Webserver Login\""); - - return HttpStatusAndStats("401", "Bad Authorization", req_ctx, res); - } - } + res = handleAuth(req_ctx, res); + if (res.result_int() / 100 == 4) // status 4xx + return res; plugin_type plugin{req_ctx.GetPlugin()}; |