diff --git a/core/http/middleware.cpp b/core/http/middleware.cpp index ce4e025..4fdf988 100644 --- a/core/http/middleware.cpp +++ b/core/http/middleware.cpp @@ -7,7 +7,7 @@ bool Middleware::on_before_handle_request_main(Request *request) { return false; } -Middleware::Middleware() { +Middleware::Middleware() : Reference() { } Middleware::~Middleware() { diff --git a/core/http/session_manager.cpp b/core/http/session_manager.cpp index 0d894f0..aaa6598 100644 --- a/core/http/session_manager.cpp +++ b/core/http/session_manager.cpp @@ -152,7 +152,7 @@ void SessionManager::load_sessions() { b->select("id, session_id"); b->from(_table_name); - //b->print(); + // b->print(); Ref r = b->run(); while (r->next_row()) { @@ -171,7 +171,7 @@ void SessionManager::load_sessions() { b->select("session_db_id, key, value"); b->from(_data_table_name); - //b->print(); + // b->print(); r = b->run(); while (r->next_row()) { @@ -213,7 +213,7 @@ void SessionManager::clear() { } String SessionManager::generate_session_id(const String &base) { - //todo make something simpler / better + // todo make something simpler / better SHA256 *h = SHA256::get(); String sid = base; @@ -229,26 +229,6 @@ String SessionManager::generate_session_id(const String &base) { return sid; } -void SessionManager::session_setup_middleware(Object *instance, Request *request) { - const String sid = request->get_cookie("session_id"); - - if (sid == "") { - //You could create a session here if you want to always assign sessions to visitors. - //Example code: - //HTTPSession *session = SessionManager::get_singleton()->create_session(); - //request->session = session; - //request->add_cookie(::Cookie("session_id", session->session_id)); - - request->next_stage(); - - return; - } - - request->session = SessionManager::get_singleton()->get_session(sid); - - request->next_stage(); -} - void SessionManager::migrate() { drop_table(); create_table(); @@ -262,7 +242,7 @@ void SessionManager::create_table() { tb->varchar("session_id", 100)->next_row(); tb->primary_key("id"); tb->ccreate_table(); - //tb->print(); + // tb->print(); tb->run_query(); tb->result = ""; @@ -274,7 +254,7 @@ void SessionManager::create_table() { tb->foreign_key("session_db_id"); tb->references(_table_name, "id"); tb->ccreate_table(); - //tb->print(); + // tb->print(); tb->run_query(); } void SessionManager::drop_table() { @@ -310,4 +290,27 @@ SessionManager::~SessionManager() { SessionManager *SessionManager::_self = nullptr; String SessionManager::_table_name = "sessions"; -String SessionManager::_data_table_name = "session_data"; \ No newline at end of file +String SessionManager::_data_table_name = "session_data"; + +bool SessionSetupMiddleware::on_before_handle_request_main(Request *request) { + const String sid = request->get_cookie("session_id"); + + if (sid == "") { + // You could create a session here if you want to always assign sessions to visitors. + // Example code: + // HTTPSession *session = SessionManager::get_singleton()->create_session(); + // request->session = session; + // request->add_cookie(::Cookie("session_id", session->session_id)); + + return false; + } + + request->session = SessionManager::get_singleton()->get_session(sid); + + return false; +} + +SessionSetupMiddleware::SessionSetupMiddleware() { +} +SessionSetupMiddleware::~SessionSetupMiddleware() { +} diff --git a/core/http/session_manager.h b/core/http/session_manager.h index 16c89ce..e6e458a 100644 --- a/core/http/session_manager.h +++ b/core/http/session_manager.h @@ -3,11 +3,12 @@ #include "core/string.h" #include "core/containers/vector.h" +#include +#include #include "core/object.h" -#include -#include +#include "middleware.h" class HTTPSession; class Request; @@ -29,8 +30,6 @@ public: virtual String generate_session_id(const String &base = ""); - static void session_setup_middleware(Object *instance, Request *request); - virtual void migrate(); virtual void create_table(); virtual void drop_table(); @@ -51,4 +50,15 @@ protected: static String _data_table_name; }; +class SessionSetupMiddleware : public Middleware { + RCPP_OBJECT(SessionSetupMiddleware, Middleware); + +public: + //returnring true means handled, false means continue + bool on_before_handle_request_main(Request *request); + + SessionSetupMiddleware(); + ~SessionSetupMiddleware(); +}; + #endif \ No newline at end of file diff --git a/core/http/web_root.cpp b/core/http/web_root.cpp index f0852f6..9a8e1a2 100644 --- a/core/http/web_root.cpp +++ b/core/http/web_root.cpp @@ -22,54 +22,21 @@ void WebRoot::setup_routes() { } void WebRoot::setup_middleware() { - // If you want sessions add this to your inherited class. Should probably be the first one. - // middlewares.push_back(HandlerInstance(::SessionManager::session_setup_middleware)); + // Middlewares get processed in the order they are in the _middlewares array - middlewares.push_back(HandlerInstance([this](Object *instance, Request *request) { this->default_routing_middleware(instance, request); })); -} + // If you want sessions add this to your inherited class. + // _middlewares.push_back(Ref(new SessionSetupMiddleware())); -void WebRoot::default_routing_middleware(Object *instance, Request *request) { - // handle default phase 1 - std::string path = request->get_path_full(); + // This one looks up users based on sessions + // _middlewares.push_back(Ref(new UserSessionSetupMiddleware())); - if (FileCache::get_singleton()->wwwroot_has_file(path)) { - send_file(path, request); - - return; - } - - // call parent handle default - - // from this this will be handled by web router node by default - HandlerInstance handler_data; - - // std::function func; - - // if (path == "/") { - if (request->get_path_segment_count() == 0) { - // quick shortcut - handler_data = index_func; - } else { - const std::string main_route = request->get_current_path_segment(); - - handler_data = main_route_map[main_route]; - - request->push_path(); - } - - if (!handler_data.handler_func) { - send_error(404, request); - - return; - } - - request->handler_instance = handler_data; - request->next_stage(); + // Same as the previous, but if you want the RBAC system to work use one of these + // _middlewares.push_back(Ref(new RBACUserSessionSetupMiddleware())); + // _middlewares.push_back(Ref(new RBACDefaultUserSessionSetupMiddleware())); } void WebRoot::default_fallback_error_handler(Request *request, int error_code) { request->compiled_body = default_generic_error_body; - request->send(); } @@ -79,9 +46,12 @@ void WebRoot::default_404_error_handler(Request *request, int error_code) { } void WebRoot::handle_request_main(Request *request) { - // request->middleware_stack = &middlewares; - // note that middlewares handle the routing -> WebRoot::default_routing_middleware by default - // request->next_stage(); + for (int i = 0; i < _middlewares.size(); ++i) { + if (_middlewares[i]->on_before_handle_request_main(request)) { + //handled + return; + } + } // handle files first if (try_send_wwwroot_file(request)) { diff --git a/core/http/web_root.h b/core/http/web_root.h index 9bc4e2a..54b73d9 100644 --- a/core/http/web_root.h +++ b/core/http/web_root.h @@ -1,30 +1,28 @@ #ifndef WEB_ROOT_H #define WEB_ROOT_H -#include "web_router_node.h" +#include "core/containers/vector.h" +#include "mutex" #include #include #include #include -#include "mutex" +#include "web_router_node.h" #include "handler_instance.h" +#include "middleware.h" class Request; -//Middleware turn into a class (reference) -//add them to a folder -//method should return bool -> true to continue, false if done +// FileCache -> set up, for this webroot, don't use singleton -//FileCache -> set up, for this webroot, don't use singleton +// clean up unused things here +// remove handler instances! -//clean up unused things here -//remove handler instances! +// Update the rest of the modules to the new systems -//Update the rest of the modules to the new systems - -//remove middleware stack from request +// remove middleware stack from request class WebRoot : public WebRouterNode { RCPP_OBJECT(WebRoot, WebRouterNode); @@ -63,6 +61,8 @@ public: std::map main_route_map; std::vector middlewares; + Vector > _middlewares; + std::map > error_handler_map; std::function default_error_handler_func; diff --git a/modules/rbac_users/rbac_user_controller.cpp b/modules/rbac_users/rbac_user_controller.cpp index 606ca24..d032323 100644 --- a/modules/rbac_users/rbac_user_controller.cpp +++ b/modules/rbac_users/rbac_user_controller.cpp @@ -7,81 +7,6 @@ #include "modules/rbac/rbac_default_permissions.h" #include "rbac_user.h" -void RBACUserController::rbac_user_session_setup_middleware(Object *instance, Request *request) { - if (request->session) { - int user_id = request->session->get_int("user_id"); - - if (user_id != 0) { - - Ref u = UserController::get_singleton()->db_get_user(user_id); - - if (u.is_valid()) { - request->reference_data["user"] = u; - } else { - // log - request->session->remove_int("user_id"); - } - } - } - - request->next_stage(); -} - -void RBACUserController::rbac_default_user_session_middleware(Object *instance, Request *request) { - // note: add a new file handler middleware func, so basic file handling is easy to set up before this - - Ref rank; - - if (request->session) { - int user_id = request->session->get_int("user_id"); - - if (user_id != 0) { - - Ref u = UserController::get_singleton()->db_get_user(user_id); - - if (u.is_valid()) { - rank = u->rbac_rank; - - request->reference_data["user"] = u; - } else { - // log - request->session->remove_int("user_id"); - } - } - } - - if (!rank.is_valid()) { - rank = RBACController::get_singleton()->get_default_rank(); - - if (!rank.is_valid()) { - if (RBACController::get_singleton()->continue_on_missing_default_rank()) { - RLOG_ERR("get_default_rank() has not been set up properly!!! Continuing!"); - request->next_stage(); - } else { - RLOG_ERR("get_default_rank() has not been set up properly!!! Sending 404!"); - request->send_error(404); - } - - return; - } - } - - if (!rank->has_permission(request, User::PERMISSION_READ)) { - if (rank->has_rank_permission(RBAC_RANK_PERMISSION_USE_REDIRECT)) { - // Note this can make the webapp prone to enumerations, if not done correctly - // e.g. redirect from /admin, but sending 404 on a non existing uri, which does not have - // a special rbac entry - request->send_redirect(RBACController::get_singleton()->get_redirect_url()); - return; - } - - request->send_error(404); - return; - } - - request->next_stage(); -} - Ref RBACUserController::db_get_user(const int id) { Ref u = UserController::db_get_user(id); @@ -131,3 +56,91 @@ RBACUserController::RBACUserController() : RBACUserController::~RBACUserController() { } + +// returnring true means handled, false means continue +bool RBACUserSessionSetupMiddleware::on_before_handle_request_main(Request *request) { + if (request->session) { + int user_id = request->session->get_int("user_id"); + + if (user_id != 0) { + + Ref u = UserController::get_singleton()->db_get_user(user_id); + + if (u.is_valid()) { + request->reference_data["user"] = u; + } else { + // log + request->session->remove_int("user_id"); + } + } + } + + return false; +} + +RBACUserSessionSetupMiddleware::RBACUserSessionSetupMiddleware() { +} +RBACUserSessionSetupMiddleware::~RBACUserSessionSetupMiddleware() { +} + +// returnring true means handled, false means continue +bool RBACDefaultUserSessionSetupMiddleware::on_before_handle_request_main(Request *request) { + // note: add a new file handler middleware func, so basic file handling is easy to set up before this + + Ref rank; + + if (request->session) { + int user_id = request->session->get_int("user_id"); + + if (user_id != 0) { + + Ref u = UserController::get_singleton()->db_get_user(user_id); + + if (u.is_valid()) { + rank = u->rbac_rank; + + request->reference_data["user"] = u; + } else { + // log + request->session->remove_int("user_id"); + } + } + } + + if (!rank.is_valid()) { + rank = RBACController::get_singleton()->get_default_rank(); + + if (!rank.is_valid()) { + if (RBACController::get_singleton()->continue_on_missing_default_rank()) { + RLOG_ERR("get_default_rank() has not been set up properly!!! Continuing!"); + return false; + } else { + RLOG_ERR("get_default_rank() has not been set up properly!!! Sending 404!"); + request->send_error(404); + return true; + } + + + } + } + + if (!rank->has_permission(request, User::PERMISSION_READ)) { + if (rank->has_rank_permission(RBAC_RANK_PERMISSION_USE_REDIRECT)) { + // Note this can make the webapp prone to enumerations, if not done correctly + // e.g. redirect from /admin, but sending 404 on a non existing uri, which does not have + // a special rbac entry + request->send_redirect(RBACController::get_singleton()->get_redirect_url()); + return true; + } + + request->send_error(404); + return true; + } + + return false; +} + +RBACDefaultUserSessionSetupMiddleware::RBACDefaultUserSessionSetupMiddleware() { +} +RBACDefaultUserSessionSetupMiddleware::~RBACDefaultUserSessionSetupMiddleware() { +} diff --git a/modules/rbac_users/rbac_user_controller.h b/modules/rbac_users/rbac_user_controller.h index 3faa30d..428eb15 100644 --- a/modules/rbac_users/rbac_user_controller.h +++ b/modules/rbac_users/rbac_user_controller.h @@ -3,17 +3,14 @@ #include "modules/users/user_controller.h" +#include "core/http/middleware.h" + class Request; class RBACUserController : public UserController { RCPP_OBJECT(RBACUserController, UserController); public: - // just session setup - static void rbac_user_session_setup_middleware(Object *instance, Request *request); - // this one also handles missing read permission / redirect - static void rbac_default_user_session_middleware(Object *instance, Request *request); - // db Ref db_get_user(const int id); @@ -29,4 +26,29 @@ public: protected: }; +// just session setup +class RBACUserSessionSetupMiddleware : public Middleware { + RCPP_OBJECT(RBACUserSessionSetupMiddleware, Middleware); + +public: + //returnring true means handled, false means continue + bool on_before_handle_request_main(Request *request); + + RBACUserSessionSetupMiddleware(); + ~RBACUserSessionSetupMiddleware(); +}; + +// this one also handles missing read permission / redirect +class RBACDefaultUserSessionSetupMiddleware : public Middleware { + RCPP_OBJECT(RBACDefaultUserSessionSetupMiddleware, Middleware); + +public: + //returnring true means handled, false means continue + bool on_before_handle_request_main(Request *request); + + RBACDefaultUserSessionSetupMiddleware(); + ~RBACDefaultUserSessionSetupMiddleware(); +}; + + #endif \ No newline at end of file diff --git a/modules/users/user_controller.cpp b/modules/users/user_controller.cpp index 1e40c0f..e5a043c 100644 --- a/modules/users/user_controller.cpp +++ b/modules/users/user_controller.cpp @@ -503,26 +503,6 @@ void UserController::create_validators() { } } -void UserController::user_session_setup_middleware(Object *instance, Request *request) { - if (request->session) { - int user_id = request->session->get_int("user_id"); - - if (user_id != 0) { - - Ref u = UserController::get_singleton()->db_get_user(user_id); - - if (u.is_valid()) { - request->reference_data["user"] = u; - } else { - // log - request->session->remove_int("user_id"); - } - } - } - - request->next_stage(); -} - Ref UserController::db_get_user(const int id) { if (id == 0) { return Ref(); @@ -810,3 +790,30 @@ FormValidator *UserController::_profile_validator = nullptr; String UserController::_path = "./"; String UserController::_table_name = "users"; + + +// returnring true means handled, false means continue +bool UserSessionSetupMiddleware::on_before_handle_request_main(Request *request) { + if (request->session) { + int user_id = request->session->get_int("user_id"); + + if (user_id != 0) { + + Ref u = UserController::get_singleton()->db_get_user(user_id); + + if (u.is_valid()) { + request->reference_data["user"] = u; + } else { + // log + request->session->remove_int("user_id"); + } + } + } + + return false; +} + +UserSessionSetupMiddleware::UserSessionSetupMiddleware() { +} +UserSessionSetupMiddleware::~UserSessionSetupMiddleware() { +} diff --git a/modules/users/user_controller.h b/modules/users/user_controller.h index 3da07dc..5b92644 100644 --- a/modules/users/user_controller.h +++ b/modules/users/user_controller.h @@ -7,6 +7,7 @@ #include "core/http/web_node.h" #include "user.h" +#include "core/http/middleware.h" class Request; class FormValidator; @@ -62,8 +63,6 @@ public: virtual void create_validators(); - static void user_session_setup_middleware(Object *instance, Request *request); - // db virtual Ref db_get_user(const int id); @@ -104,4 +103,17 @@ protected: static String _table_name; }; +// just session setup +class UserSessionSetupMiddleware : public Middleware { + RCPP_OBJECT(UserSessionSetupMiddleware, Middleware); + +public: + //returnring true means handled, false means continue + bool on_before_handle_request_main(Request *request); + + UserSessionSetupMiddleware(); + ~UserSessionSetupMiddleware(); +}; + + #endif \ No newline at end of file