fastcgi::Filter
class: class Filter { public: Filter(); virtual ~Filter(); Filter(const Filter&) = delete; Filter& operator=(const Filter&) = delete; virtual void onThreadStart(); virtual void doFilter(Request *req, HandlerContext *context, std::function<void(Request *req, HandlerContext *context)> next) = 0; };
<modules> <module name="example" path="./example.so"/> ... </modules> <components> <component name="example_filter_1" type="example:filter1"> <logger>daemon-logger</logger> </component> <component name="example_filter_2" type="example:filter2"> <logger>daemon-logger</logger> </component> ... </components>
<handlers urlPrefix="/myapp"> <filter> <component name="example_filter_1"/> </filter> ... </handlers>
<handlers urlPrefix="/myapp"> <filter url="/.*"> <component name="example_filter_2"/> </filter> ... </handlers>
next
function passed to it via the parameter list. To break a chain, a filter can return control without calling the next
function.Basic access authentication
, Form authentication
, and Delegated authentication
.REMOTE_USER
.Security Realm
. <modules> <module name="auth" path="/usr/local/lib64/fastcgi3/fastcgi3-authenticator.so"/> ... </modules> <components> <component name="form_authenticator" type="auth:form-authenticator"> <form-page>/login</form-page> <realm>example_realm</realm> <logger>daemon-logger</logger> <store-request>true</store-request> </component> <component name="basic_authenticator" type="auth:basic-authenticator"> <realm>example_realm</realm> <logger>daemon-logger</logger> </component> <component name="delegated_authenticator" type="auth:delegated-authenticator"> <realm>example_realm</realm> <logger>daemon-logger</logger> </component> ... </components>
<handlers urlPrefix="/myapp"> <filter url="/.*"> <component name="form_authenticator"/> </filter> ... </handlers>
Security Realm
, which should be implemented in the application as an extension of the fastcgi::security::Realm
class: class Realm : public fastcgi::Component { public: Realm(std::shared_ptr<fastcgi::ComponentContext> context); virtual ~Realm(); virtual void onLoad() override; virtual void onUnload() override; virtual std::shared_ptr<Subject> authenticate(const std::string& username, const std::string& credentials); virtual std::shared_ptr<Subject> getSubject(const std::string& username); const std::string& getName() const; protected: std::string name_; std::shared_ptr<fastcgi::Logger> logger_; };
Security Realm
with specifying a list of users directly in the configuration file: class ExampleRealm : virtual public fastcgi::security::Realm { public: ExampleRealm(std::shared_ptr<fastcgi::ComponentContext> context); virtual ~ExampleRealm(); virtual void onLoad() override; virtual void onUnload() override; virtual std::shared_ptr<fastcgi::security::Subject> authenticate(const std::string& username, const std::string& credentials) override; virtual std::shared_ptr<fastcgi::security::Subject> getSubject(const std::string& username) override; private: std::unordered_map<std::string, std::shared_ptr<UserData>> users_; }; ExampleRealm::ExampleRealm(std::shared_ptr<fastcgi::ComponentContext> context) : fastcgi::security::Realm(context) { const fastcgi::Config *config = context->getConfig(); const std::string componentXPath = context->getComponentXPath(); std::vector<std::string> users; config->subKeys(componentXPath+"/users/user[count(@name)=1]", users); for (auto& u : users) { std::string username = config->asString(u + "/@name", ""); std::shared_ptr<UserData> data = std::make_shared<UserData>(); data->password = config->asString(u + "/@password", ""); std::vector<std::string> roles; config->subKeys(u+"/role[count(@name)=1]", roles); for (auto& r : roles) { data->roles.push_back(config->asString(r + "/@name", "")); } users_.insert({username, std::move(data)}); } } ExampleRealm::~ExampleRealm() { ; } void ExampleRealm::onLoad() { fastcgi::security::Realm::onLoad(); } void ExampleRealm::onUnload() { fastcgi::security::Realm::onUnload(); } std::shared_ptr<fastcgi::security::Subject> ExampleRealm::authenticate(const std::string& username, const std::string& credentials) { std::shared_ptr<fastcgi::security::Subject> subject; auto it = users_.find(username); if (users_.end()!=it && it->second && credentials==it->second->password) { subject = std::make_shared<fastcgi::security::Subject>(); for (auto &r : it->second->roles) { subject->setPrincipal(std::make_shared<fastcgi::security::Principal>(r)); } subject->setReadOnly(); } return subject; } std::shared_ptr<fastcgi::security::Subject> ExampleRealm::getSubject(const std::string& username) { std::shared_ptr<fastcgi::security::Subject> subject; auto it = users_.find(username); if (users_.end()!=it && it->second) { subject = std::make_shared<fastcgi::security::Subject>(); for (auto &r : it->second->roles) { subject->setPrincipal(std::make_shared<fastcgi::security::Principal>(r)); } subject->setReadOnly(); } return subject; }
<modules> <module name="example" path="./example.so"/> ... </modules> <components> <component name="example_realm" type="example:example-realm"> <name>Example Realm</name> <logger>daemon-logger</logger> <users> <user name="test1" password="1234"> <role name="ROLE1"/> <role name="ROLE2"/> <role name="ROLE3"/> </user> <user name="test2" password="5678"> <role name="ROLE1"/> <role name="ROLE4"/> </user> </users> </component> ... </components>
Form Authentication
authentication filter requires activation of session support. At the same time, sessions are used to save the initial request from unauthenticated clients.<security-constraints>
element in the configuration file is used: <security-constraints> <constraint url=".*" role="ROLE1"/> <constraint url="/servlet" role="ROLE2"/> </security-constraints>
fastcgi::Request
and fastcgi::HttpRequest
classes provide methods: std::shared_ptr<security::Subject> Request::getSubject() const; bool Request::isUserInRole(const std::string& roleName) const; template<class T> bool Request::isUserInRole(const std::string &roleName) { return getSubject()->hasPrincipal<T>(roleName); }
getSubject()
method returns a pointer to an “anonymous” object with an empty set of roles and returning true
when calling the following method: bool security::Subject::isAnonymous() const;
Simple Session Manager
. To activate it, add the following to the configuration file: <modules> <module name="manager" path="/usr/local/lib64/fastcgi3/fastcgi3-session-manager.so"/> ... </modules> <components> <component name="session-manager" type="manager:simple-session-manager"> <logger>daemon-logger</logger> </component> ... </components> <session attach="true" component="session-manager"> <timeout>30</timeout> </session>
fastcgi::Request
class provides a method: std::shared_ptr<Session> Request::getSession();
fastcgi::Session
class provides the following methods: virtual void setAttribute(const std::string &name, const core::any &value); virtual core::any getAttribute(const std::string &name) const; virtual bool hasAttribute(const std::string &name) const; virtual void removeAttribute(const std::string& name); virtual void removeAllAttributes(); std::type_info const& type(const std::string &name) const; std::size_t addListener(ListenerType f); void removeListener(std::size_t index);
Simple Session Manager
does not have container cluster support, so if you use more than one container on the load balancer, you should configure “sticky sessions”.fastcgi::Request
and fastcgi::Handler
classes, the container provides the wrapper classes fastcgi::HttpRequest
, fastcgi::HttpResponse
and fastcgi::Servlet
. <%@ page class="TimeHandler" %> <%@ component name="TestServlet" %> <%! #include <chrono> %> <% auto p = std::chrono::system_clock::now(); auto t = std::chrono::system_clock::to_time_t(p); %> <html> <head> <title>Time Sample</title> </head> <body> <h1>Time Sample</h1> <p><%= std::ctime(&t) %></p> </body> </html>
Source: https://habr.com/ru/post/280814/
All Articles