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()};  | 
