add support for more cookie flags in Request::AddCookie() method

changed in config options:
- renamed: http_session_id_name to session_cookie_name
- add config options: session_cookie_path, session_cookie_domain, session_cookie_same_site,
  session_cookie_http_only, session_cookie_secure
This commit is contained in:
Tomasz Sowa 2022-09-08 05:40:44 +02:00
parent 222a1c8a1f
commit 05ecac8426
8 changed files with 174 additions and 55 deletions

View File

@ -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");

View File

@ -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

View File

@ -1646,6 +1646,79 @@ bool is_in_list(const std::wstring & item, const std::set<std::wstring> & 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

View File

@ -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

View File

@ -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<CookieSameSite>(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

View File

@ -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<typename NameType, typename ValueType>
void AddCookie(const NameType & name, const ValueType & value, pt::Date * expires = 0);
template<typename NameType, typename ValueType>
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<typename NameType, typename ValueType>
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<typename NameType, typename ValueType>
void Request::AddCookie(const NameType & name, const ValueType & value, pt::Date & expires)
{
AddCookie(name, value, &expires);
}
} // namespace Winix
#endif

View File

@ -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<std::wstring, PostFile> PostFileTab;
typedef std::vector<Param> ParamTab;

View File

@ -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() )
{