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