diff --git a/winixd/core/config.cpp b/winixd/core/config.cpp index 0aa2f65..6c51056 100644 --- a/winixd/core/config.cpp +++ b/winixd/core/config.cpp @@ -195,7 +195,13 @@ void Config::AssignValues() use_internal_session_mechanism = Bool(L"use_internal_session_mechanism", true); use_internal_loggin_mechanism = Bool(L"use_internal_loggin_mechanism", true); - http_session_id_name = Text(L"http_session_id_name", L"session_id"); + session_cookie_name = Text(L"session_cookie_name", L"session_id"); + session_cookie_path = Text(L"session_cookie_path", L"/"); + session_cookie_domain = Text(L"session_cookie_domain", L""); + session_cookie_same_site = Int(L"session_cookie_same_site", 0); + session_cookie_http_only = Bool(L"session_cookie_http_only", false); + session_cookie_secure = Bool(L"session_cookie_secure", false); + db_conn_string = Text(L"db_conn_string"); db_host = Text(L"db_host"); db_hostaddr = Text(L"db_hostaddr"); diff --git a/winixd/core/config.h b/winixd/core/config.h index c0461a0..3715e44 100644 --- a/winixd/core/config.h +++ b/winixd/core/config.h @@ -287,7 +287,33 @@ public: bool use_internal_loggin_mechanism; // the name of the cookie which has the session identifier - std::wstring http_session_id_name; + std::wstring session_cookie_name; + + // session cookie path + // default: / + std::wstring session_cookie_path; + + // session cookie domain + // if empty then the domain will be equal base_url + // default: empty + std::wstring session_cookie_domain; + + // session cookie samesite attribute + // 0 - dont set the attribute + // 1 - Strict + // 2 - Lax + // 3 - None + // (values the same as values from CookieSameSite enum) + // default: 0 + int session_cookie_same_site; + + // whether or not set HttpOnly attribute on the session cookie + // default: false + bool session_cookie_http_only; + + // whether or not set Secure attribute on the session cookie + // default: false + bool session_cookie_secure; // string used in a place where is a user (or group) selected // !! IMPROVE ME should be moved to locales diff --git a/winixd/core/misc.cpp b/winixd/core/misc.cpp index 0bde9ad..343cc26 100644 --- a/winixd/core/misc.cpp +++ b/winixd/core/misc.cpp @@ -1646,6 +1646,79 @@ bool is_in_list(const std::wstring & item, const std::set & list) } +void cookie_same_site_to_stream(CookieSameSite same_site, pt::Stream & stream) +{ + switch(same_site) + { + case CookieSameSite::samesite_strict: + stream << L"Strict"; + break; + + case CookieSameSite::samesite_lax: + stream << L"Lax"; + break; + + case CookieSameSite::samesite_none: + stream << L"None"; + break; + + default: + break; + } +} + + +void prepare_cookie_string( + pt::Stream & cookie, + const std::wstring * value_string, + const pt::Stream * value_stream, + pt::Date * expires, + const std::wstring * path, + const std::wstring * domain, + CookieSameSite cookie_same_site, + bool http_only, + bool secure) +{ + if( value_string ) + cookie << *value_string; + + if( value_stream ) + cookie << *value_stream; + + if( cookie.empty() ) + cookie << L"\"\""; // cookie empty value + + if( expires ) + cookie << L"; expires=" << DateToStrCookie(*expires) << L" GMT"; + + if( path && !path->empty() ) + { + cookie << L"; path=" << *path; + } + + if( domain && !domain->empty() ) + cookie << L"; domain=" << *domain; + + if( cookie_same_site != CookieSameSite::samesite_notset ) + { + cookie << L"; SameSite="; + cookie_same_site_to_stream(cookie_same_site, cookie); + } + + if( http_only ) + cookie << L"; HttpOnly"; + + /* + don't use '; secure' flag if you are using both sites (with SSL + and without SSL) -- with secure flag the cookie is sent only through + SSL and if you accidentally open a new window without SSL (http://) + then winix will create a new session for you and the previous session (https://) + will be lost (the session cookie will be overwritten in the client's browser) + */ + if( secure ) + cookie << L"; Secure"; +} + } // namespace Winix diff --git a/winixd/core/misc.h b/winixd/core/misc.h index 32f0e36..4da91e7 100644 --- a/winixd/core/misc.h +++ b/winixd/core/misc.h @@ -1055,6 +1055,22 @@ bool is_in_list_generic(const std::wstring & item, const ContainerType & list) } +void cookie_same_site_to_stream(CookieSameSite same_site, pt::Stream & stream); + + +void prepare_cookie_string( + pt::Stream & out_stream, + const std::wstring * value_string = nullptr, + const pt::Stream * value_stream = nullptr, + pt::Date * expires = nullptr, + const std::wstring * path = nullptr, + const std::wstring * domain = nullptr, + CookieSameSite cookie_same_site = CookieSameSite::samesite_notset, + bool http_only = false, + bool secure = false); + + + } // namespace Winix diff --git a/winixd/core/request.cpp b/winixd/core/request.cpp index 063b6c6..266057d 100644 --- a/winixd/core/request.cpp +++ b/winixd/core/request.cpp @@ -1521,12 +1521,12 @@ void Request::PrepareSessionCookie() if( !session->puser || !session->remember_me ) { - AddCookie(config->http_session_id_name, cookie_id_string); + AddDefaultSessionCookie(cookie_id_string); } else { pt::Date expires = start_time + config->session_remember_max_idle; - AddCookie(config->http_session_id_name, cookie_id_string, expires); + AddDefaultSessionCookie(cookie_id_string, &expires); } } @@ -2143,6 +2143,39 @@ void Request::PutMethodName(pt::Stream & stream) +void Request::AddCookie( + const std::wstring & name, + const std::wstring * value_string, + const pt::Stream * value_stream, + pt::Date * expires, + const std::wstring * path, + const std::wstring * domain, + CookieSameSite cookie_same_site, + bool http_only, + bool secure) +{ + pt::WTextStream cookie; + prepare_cookie_string(cookie, value_string, value_stream, expires, path, domain, cookie_same_site, http_only, secure); + out_cookies.add_stream(name, cookie); +} + + +void Request::AddDefaultSessionCookie(const std::wstring & value, pt::Date * expires) +{ + AddCookie( + config->session_cookie_name, + &value, + nullptr, + expires, + &config->session_cookie_path, + &config->session_cookie_domain, + static_cast(config->session_cookie_same_site), + config->session_cookie_http_only, + config->session_cookie_secure + ); +} + + void Request::FinishRequest() { modify_status_code_if_needed(); // will be removed diff --git a/winixd/core/request.h b/winixd/core/request.h index 6eda69a..733fe14 100644 --- a/winixd/core/request.h +++ b/winixd/core/request.h @@ -494,16 +494,18 @@ public: std::wstring * PostVarp(const wchar_t * var); std::wstring * PostVarp(const std::wstring & var); + void AddCookie( + const std::wstring & name, + const std::wstring * value_string = nullptr, + const pt::Stream * value_stream = nullptr, + pt::Date * expires = nullptr, + const std::wstring * path = nullptr, + const std::wstring * domain = nullptr, + CookieSameSite cookie_same_site = CookieSameSite::samesite_notset, + bool http_only = false, + bool secure = false); - // setting a cookie - // name - cookie name (either const wchar_t, or std::wstring or pt::WTextStream) - // value - cookie value (can be everything which can be put to pt::WTextStream stream) - // the return std::wstring reference is a reference to the cookie inserted value (in out_cookies structure) - template - void AddCookie(const NameType & name, const ValueType & value, pt::Date * expires = 0); - - template - void AddCookie(const NameType & name, const ValueType & value, pt::Date & expires); + void AddDefaultSessionCookie(const std::wstring & value, pt::Date * expires = nullptr); bool has_frame(const wchar_t * frame); bool has_frame(const std::wstring & frame); @@ -615,47 +617,6 @@ private: - -template -void Request::AddCookie(const NameType & name, const ValueType & value, pt::Date * expires) -{ - pt::WTextStream cookie; - - cookie << value; - - if( cookie.empty() ) - cookie << L"\"\""; // cookie empty value - - if( expires ) - cookie << L"; expires=" << DateToStrCookie(*expires) << L" GMT"; - - cookie << L"; path=/; domain=" << config->base_url; - - /* - !! IMPROVE ME add an option to the config - - don't use '; secure' flag if you are using both sites (with SSL - and without SSL) -- with secure flag the cookie is sent only through - SSL and if you accidentally open a new window without SSL (http://) - then winix will create a new session for you and the previous session (https://) - will be lost (the session cookie will be overwritten in the client's browser) - */ - - out_cookies.add_stream(name, cookie); -} - - -template -void Request::AddCookie(const NameType & name, const ValueType & value, pt::Date & expires) -{ - AddCookie(name, value, &expires); -} - - - - - - } // namespace Winix #endif diff --git a/winixd/core/requesttypes.h b/winixd/core/requesttypes.h index cf9ad61..dbf5277 100644 --- a/winixd/core/requesttypes.h +++ b/winixd/core/requesttypes.h @@ -66,6 +66,10 @@ struct Param }; +enum CookieSameSite {samesite_notset = 0, samesite_strict = 1, samesite_lax = 2, samesite_none = 3}; + + + // some global types used by Request class typedef std::map PostFileTab; typedef std::vector ParamTab; diff --git a/winixd/core/sessionmanager.cpp b/winixd/core/sessionmanager.cpp index 65b7aa8..365ace3 100644 --- a/winixd/core/sessionmanager.cpp +++ b/winixd/core/sessionmanager.cpp @@ -479,7 +479,7 @@ Session * SessionManager::PrepareSession() { if( !IsIPBanned() ) { - CookieTab::iterator i = cur->request->cookie_tab.find(config->http_session_id_name); + CookieTab::iterator i = cur->request->cookie_tab.find(config->session_cookie_name); if( i != cur->request->cookie_tab.end() ) {