Skip to content

Commit 30fb508

Browse files
committed
support individual SameSite settings on session/state/csrf cookies
by adding 2 more arguments to OIDCCookieSameSite Signed-off-by: Hans Zandbelt <[email protected]>
1 parent 234d5f0 commit 30fb508

File tree

10 files changed

+114
-20
lines changed

10 files changed

+114
-20
lines changed

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
11/07/2025
2+
- support individual SameSite cookie settings on the session cookie, state cookie and Discovery CSRF
3+
cookie by adding 2 more arguments to OIDCCookieSameSite
4+
15
11/05/2025
26
- test: add jose.c coverage tests
37

auth_openidc.conf

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@
262262
# The response mode used (this serves as default value for discovered OPs too)
263263
# When not defined the default response mode for the requested flow (OIDCResponseType) is used.
264264
# NB: this can be overridden on a per-OP basis in the .conf file using the key: response_mode
265+
# Note that form_post response mode requires SameSite=None on the State cookie, see OIDCCookieSameSite.
266+
# When not defined the default is query
265267
#OIDCResponseMode [fragment|query|form_post]
266268

267269
# Only used for a single static provider has been configured, see below in OpenID Connect Provider.
@@ -593,8 +595,13 @@
593595
# conditionally overridden using an environment variable in the Apache config as in:
594596
# SetEnvIf User-Agent ".*IOS.*" OIDC_SET_COOKIE_APPEND=;
595597
#
598+
# One can specify individual SameSite settings for the session cookie, state cookie and CSRF discovery cookie as follows:
599+
# OIDCCookieSameSite <session-cookie-same-site> [<state-cookie-same-site>] [<discovery-csrf-same-site>]
600+
# E.g. to allow form_post response mode one could specify:
601+
# OIDCCookieSameSite Strict None
602+
#
596603
# When not defined the default is On (Lax).
597-
#OIDCCookieSameSite [ On | Off | Strict | Lax | None | Disabled ]
604+
#OIDCCookieSameSite On|Off|Strict|Lax|None|Disabled [On|Off|Lax|None|Disabled] [On|Off|Strict|Lax|None|Disabled]
598605

599606
# Specify the names of cookies to pick up from the browser and send along on backchannel
600607
# calls to the OP and AS endpoints. This can be used for load-balancing purposes.

src/cfg/cfg.c

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,8 @@ OIDC_CFG_MEMBER_FUNCS_BOOL(cookie_http_only, OIDC_DEFAULT_COOKIE_HTTPONLY)
573573
/*
574574
* define which header we use for calculating the fingerprint of the state during authentication
575575
*/
576-
const char *oidc_cmd_cookie_same_site_set(cmd_parms *cmd, void *m, const char *arg) {
576+
const char *oidc_cmd_cookie_same_site_session_set(cmd_parms *cmd, void *m, const char *arg1, const char *arg2,
577+
const char *arg3) {
577578
oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
578579
// NB: On is made equal to Lax here and Off is equal to None (backwards compatibility)
579580
static const oidc_cfg_option_t options[] = {{OIDC_SAMESITE_COOKIE_NONE, OIDC_SAMESITE_COOKIE_OFF_STR},
@@ -582,13 +583,34 @@ const char *oidc_cmd_cookie_same_site_set(cmd_parms *cmd, void *m, const char *a
582583
{OIDC_SAMESITE_COOKIE_NONE, OIDC_SAMESITE_COOKIE_NONE_STR},
583584
{OIDC_SAMESITE_COOKIE_LAX, OIDC_SAMESITE_COOKIE_LAX_STR},
584585
{OIDC_SAMESITE_COOKIE_STRICT, OIDC_SAMESITE_COOKIE_STRICT_STR}};
585-
const char *rv = oidc_cfg_parse_option_ignore_case(cmd->pool, options, OIDC_CFG_OPTIONS_SIZE(options), arg,
586-
&cfg->cookie_same_site);
586+
const char *rv = oidc_cfg_parse_option_ignore_case(cmd->pool, options, OIDC_CFG_OPTIONS_SIZE(options), arg1,
587+
&cfg->cookie_same_site_session);
588+
if ((rv == NULL) && (arg2 != NULL)) {
589+
static const oidc_cfg_option_t state_options[] = {
590+
{OIDC_SAMESITE_COOKIE_NONE, OIDC_SAMESITE_COOKIE_OFF_STR},
591+
{OIDC_SAMESITE_COOKIE_LAX, OIDC_SAMESITE_COOKIE_ON_STR},
592+
{OIDC_SAMESITE_COOKIE_DISABLED, OIDC_SAMESITE_COOKIE_DISABLED_STR},
593+
{OIDC_SAMESITE_COOKIE_NONE, OIDC_SAMESITE_COOKIE_NONE_STR},
594+
{OIDC_SAMESITE_COOKIE_LAX, OIDC_SAMESITE_COOKIE_LAX_STR}};
595+
rv = oidc_cfg_parse_option_ignore_case(cmd->pool, state_options, OIDC_CFG_OPTIONS_SIZE(state_options),
596+
arg2, &cfg->cookie_same_site_state);
597+
}
598+
if ((rv == NULL) && (arg3 != NULL)) {
599+
rv = oidc_cfg_parse_option_ignore_case(cmd->pool, options, OIDC_CFG_OPTIONS_SIZE(options), arg3,
600+
&cfg->cookie_same_site_discovery_csrf);
601+
}
587602
return OIDC_CONFIG_DIR_RV(cmd, rv);
588603
}
589604

590605
#define OIDC_DEFAULT_COOKIE_SAME_SITE OIDC_SAMESITE_COOKIE_LAX
591-
OIDC_CFG_MEMBER_FUNC_TYPE_GET(cookie_same_site, oidc_samesite_cookie_t, OIDC_DEFAULT_COOKIE_SAME_SITE)
606+
OIDC_CFG_MEMBER_FUNC_TYPE_GET(cookie_same_site_session, oidc_samesite_cookie_t, OIDC_DEFAULT_COOKIE_SAME_SITE)
607+
608+
#define OIDC_DEFAULT_COOKIE_SAME_SITE_STATE oidc_cfg_cookie_same_site_session_get(cfg)
609+
OIDC_CFG_MEMBER_FUNC_TYPE_GET(cookie_same_site_state, oidc_samesite_cookie_t, OIDC_DEFAULT_COOKIE_SAME_SITE_STATE)
610+
611+
#define OIDC_DEFAULT_COOKIE_SAME_SITE_CSRF_DISCOVERY oidc_cfg_cookie_same_site_session_get(cfg)
612+
OIDC_CFG_MEMBER_FUNC_TYPE_GET(cookie_same_site_discovery_csrf, oidc_samesite_cookie_t,
613+
OIDC_DEFAULT_COOKIE_SAME_SITE_CSRF_DISCOVERY)
592614

593615
#define OIDC_DEFAULT_SESSION_FALLBACK_TO_COOKIE 0
594616
OIDC_CFG_MEMBER_FUNCS_BOOL(session_cache_fallback_to_cookie, OIDC_DEFAULT_SESSION_FALLBACK_TO_COOKIE)
@@ -710,7 +732,10 @@ void *oidc_cfg_server_create(apr_pool_t *pool, server_rec *svr) {
710732
c->remote_user_claim.reg_exp = NULL;
711733
c->remote_user_claim.replace = NULL;
712734
c->cookie_http_only = OIDC_CONFIG_POS_INT_UNSET;
713-
c->cookie_same_site = OIDC_CONFIG_POS_INT_UNSET;
735+
736+
c->cookie_same_site_session = OIDC_CONFIG_POS_INT_UNSET;
737+
c->cookie_same_site_state = OIDC_CONFIG_POS_INT_UNSET;
738+
c->cookie_same_site_discovery_csrf = OIDC_CONFIG_POS_INT_UNSET;
714739

715740
c->outgoing_proxy.host_port = NULL;
716741
c->outgoing_proxy.username_password = NULL;
@@ -834,8 +859,16 @@ void *oidc_cfg_server_merge(apr_pool_t *pool, void *BASE, void *ADD) {
834859

835860
c->cookie_http_only =
836861
add->cookie_http_only != OIDC_CONFIG_POS_INT_UNSET ? add->cookie_http_only : base->cookie_http_only;
837-
c->cookie_same_site =
838-
add->cookie_same_site != OIDC_CONFIG_POS_INT_UNSET ? add->cookie_same_site : base->cookie_same_site;
862+
863+
c->cookie_same_site_session = add->cookie_same_site_session != OIDC_CONFIG_POS_INT_UNSET
864+
? add->cookie_same_site_session
865+
: base->cookie_same_site_session;
866+
c->cookie_same_site_state = add->cookie_same_site_state != OIDC_CONFIG_POS_INT_UNSET
867+
? add->cookie_same_site_state
868+
: base->cookie_same_site_state;
869+
c->cookie_same_site_discovery_csrf = add->cookie_same_site_discovery_csrf != OIDC_CONFIG_POS_INT_UNSET
870+
? add->cookie_same_site_discovery_csrf
871+
: base->cookie_same_site_discovery_csrf;
839872

840873
if (add->outgoing_proxy.host_port != NULL) {
841874
c->outgoing_proxy.host_port = add->outgoing_proxy.host_port;

src/cfg/cfg.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ OIDC_CFG_MEMBER_FUNCS_DECL(default_sso_url, const char *)
224224
OIDC_CFG_MEMBER_FUNCS_DECL(default_slo_url, const char *)
225225
OIDC_CFG_MEMBER_FUNCS_DECL(cookie_domain, const char *)
226226
OIDC_CFG_MEMBER_FUNCS_DECL(cookie_http_only, int)
227-
OIDC_CFG_MEMBER_FUNCS_DECL(cookie_same_site, oidc_samesite_cookie_t)
228227
OIDC_CFG_MEMBER_FUNCS_DECL(claim_delimiter, const char *)
229228
OIDC_CFG_MEMBER_FUNCS_DECL(claim_prefix, const char *)
230229
OIDC_CFG_MEMBER_FUNCS_DECL(state_timeout, int)
@@ -254,6 +253,9 @@ OIDC_CFG_MEMBER_FUNCS_DECL(crypto_passphrase, const oidc_crypto_passphrase_t *,
254253
OIDC_CFG_MEMBER_FUNCS_DECL(max_number_of_state_cookies, int, const char *)
255254

256255
// 3 args
256+
OIDC_CFG_MEMBER_FUNCS_DECL(cookie_same_site_session, oidc_samesite_cookie_t, const char *, const char *)
257+
OIDC_CFG_MEMBER_FUNC_GET_DECL(cookie_same_site_state, oidc_samesite_cookie_t)
258+
OIDC_CFG_MEMBER_FUNC_GET_DECL(cookie_same_site_discovery_csrf, oidc_samesite_cookie_t)
257259
OIDC_CFG_MEMBER_FUNCS_DECL(remote_user_claim, const oidc_remote_user_claim_t *, const char *, const char *)
258260
OIDC_CFG_MEMBER_FUNCS_DECL(outgoing_proxy, const oidc_http_outgoing_proxy_t *, const char *, const char *)
259261
OIDC_CFG_MEMBER_FUNCS_DECL(http_timeout_short, oidc_http_timeout_t *, const char *, const char *)

src/cfg/cfg_int.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ struct oidc_cfg_t {
150150
int session_cookie_chunk_size;
151151
char *cookie_domain;
152152
int cookie_http_only;
153-
int cookie_same_site;
153+
/* samesite cookie settings */
154+
int cookie_same_site_session;
155+
int cookie_same_site_state;
156+
int cookie_same_site_discovery_csrf;
154157

155158
int state_timeout;
156159
int max_number_of_state_cookies;

src/cfg/cmds.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ const command_rec oidc_cfg_cmds[] = {
103103
cookie_http_only,
104104
"Defines whether or not the cookie httponly flag is set on cookies."),
105105
OIDC_CFG_CMD(
106-
AP_INIT_TAKE1,
106+
AP_INIT_TAKE123,
107107
OIDCCookieSameSite,
108-
cookie_same_site,
108+
cookie_same_site_session,
109109
"Defines whether or not the cookie Same-Site flag is set on cookies."),
110110
OIDC_CFG_CMD(
111111
AP_INIT_TAKE123,

src/handle/discovery.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ apr_byte_t oidc_is_discovery_response(request_rec *r, oidc_cfg_t *cfg) {
7676

7777
static const char *oidc_discovery_csrf_cookie_samesite(request_rec *r, oidc_cfg_t *c) {
7878
const char *rv = NULL;
79-
switch (oidc_cfg_cookie_same_site_get(c)) {
79+
switch (oidc_cfg_cookie_same_site_discovery_csrf_get(c)) {
8080
case OIDC_SAMESITE_COOKIE_STRICT:
8181
rv = OIDC_HTTP_COOKIE_SAMESITE_STRICT;
8282
break;

src/handle/request.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ apr_byte_t oidc_request_check_cookie_domain(request_rec *r, oidc_cfg_t *c, const
9595
return TRUE;
9696
}
9797

98-
static const char *oidc_request_samesite_cookie(request_rec *r, struct oidc_cfg_t *c) {
98+
static const char *oidc_request_samesite_state_cookie(request_rec *r, struct oidc_cfg_t *c) {
9999
const char *rv = NULL;
100-
switch (oidc_cfg_cookie_same_site_get(c)) {
100+
switch (oidc_cfg_cookie_same_site_state_get(c)) {
101101
case OIDC_SAMESITE_COOKIE_STRICT:
102102
case OIDC_SAMESITE_COOKIE_LAX:
103103
rv = OIDC_HTTP_COOKIE_SAMESITE_LAX;
@@ -146,7 +146,7 @@ static int oidc_request_authorization_set_cookie(request_rec *r, oidc_cfg_t *c,
146146
const char *cookieName = oidc_state_cookie_name(r, state);
147147

148148
/* set it as a cookie */
149-
oidc_http_set_cookie(r, cookieName, cookieValue, -1, oidc_request_samesite_cookie(r, c));
149+
oidc_http_set_cookie(r, cookieName, cookieValue, -1, oidc_request_samesite_state_cookie(r, c));
150150

151151
return OK;
152152
}

src/session.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,9 @@ static apr_byte_t oidc_session_load_cache(request_rec *r, oidc_session_t *z) {
193193
return rc;
194194
}
195195

196-
static const char *oidc_session_samesite_cookie(request_rec *r, struct oidc_cfg_t *c, int first_time) {
196+
static const char *oidc_session_cookie_samesite(request_rec *r, struct oidc_cfg_t *c, int first_time) {
197197
const char *rv = NULL;
198-
switch (oidc_cfg_cookie_same_site_get(c)) {
198+
switch (oidc_cfg_cookie_same_site_session_get(c)) {
199199
case OIDC_SAMESITE_COOKIE_STRICT:
200200
rv = first_time ? OIDC_HTTP_COOKIE_SAMESITE_LAX : OIDC_HTTP_COOKIE_SAMESITE_STRICT;
201201
break;
@@ -238,7 +238,7 @@ static apr_byte_t oidc_session_save_cache(request_rec *r, oidc_session_t *z, apr
238238
/* set the uuid in the cookie */
239239
oidc_http_set_cookie(r, oidc_cfg_dir_cookie_get(r), z->uuid,
240240
oidc_cfg_persistent_session_cookie_get(c) ? z->expiry : -1,
241-
oidc_session_samesite_cookie(r, c, first_time));
241+
oidc_session_cookie_samesite(r, c, first_time));
242242

243243
} else {
244244

@@ -278,7 +278,7 @@ static apr_byte_t oidc_session_save_cookie(request_rec *r, oidc_session_t *z, ap
278278
oidc_http_set_chunked_cookie(
279279
r, oidc_cfg_dir_cookie_get(r), cookieValue, oidc_cfg_persistent_session_cookie_get(c) ? z->expiry : -1,
280280
oidc_cfg_session_cookie_chunk_size_get(c),
281-
(z->state == NULL) ? OIDC_HTTP_COOKIE_SAMESITE_NONE(c, r) : oidc_session_samesite_cookie(r, c, first_time));
281+
(z->state == NULL) ? OIDC_HTTP_COOKIE_SAMESITE_NONE(c, r) : oidc_session_cookie_samesite(r, c, first_time));
282282

283283
return TRUE;
284284
}

test/test_cfg.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,50 @@ END_TEST
125125

126126
#endif
127127

128+
START_TEST(test_cmd_cookie_same_site) {
129+
cmd_parms *cmd = oidc_test_cmd_get(OIDCCookieSameSite);
130+
oidc_cfg_t *cfg = oidc_test_cfg_get();
131+
132+
// default is Lax
133+
ck_assert_int_eq(oidc_cfg_cookie_same_site_session_get(cfg), OIDC_SAMESITE_COOKIE_LAX);
134+
ck_assert_int_eq(oidc_cfg_cookie_same_site_state_get(cfg), OIDC_SAMESITE_COOKIE_LAX);
135+
ck_assert_int_eq(oidc_cfg_cookie_same_site_discovery_csrf_get(cfg), OIDC_SAMESITE_COOKIE_LAX);
136+
137+
ck_assert_ptr_null(oidc_cmd_cookie_same_site_session_set(cmd, NULL, "Lax", NULL, NULL));
138+
ck_assert_int_eq(oidc_cfg_cookie_same_site_session_get(cfg), OIDC_SAMESITE_COOKIE_LAX);
139+
ck_assert_int_eq(oidc_cfg_cookie_same_site_state_get(cfg), OIDC_SAMESITE_COOKIE_LAX);
140+
ck_assert_int_eq(oidc_cfg_cookie_same_site_discovery_csrf_get(cfg), OIDC_SAMESITE_COOKIE_LAX);
141+
142+
// state and csrf cookies should inherit from session cookie */
143+
ck_assert_ptr_null(oidc_cmd_cookie_same_site_session_set(cmd, NULL, "Strict", NULL, NULL));
144+
ck_assert_int_eq(oidc_cfg_cookie_same_site_session_get(cfg), OIDC_SAMESITE_COOKIE_STRICT);
145+
ck_assert_int_eq(oidc_cfg_cookie_same_site_state_get(cfg), OIDC_SAMESITE_COOKIE_STRICT);
146+
ck_assert_int_eq(oidc_cfg_cookie_same_site_discovery_csrf_get(cfg), OIDC_SAMESITE_COOKIE_STRICT);
147+
148+
ck_assert_ptr_null(oidc_cmd_cookie_same_site_session_set(cmd, NULL, "None", NULL, NULL));
149+
ck_assert_int_eq(oidc_cfg_cookie_same_site_session_get(cfg), OIDC_SAMESITE_COOKIE_NONE);
150+
ck_assert_int_eq(oidc_cfg_cookie_same_site_state_get(cfg), OIDC_SAMESITE_COOKIE_NONE);
151+
ck_assert_int_eq(oidc_cfg_cookie_same_site_discovery_csrf_get(cfg), OIDC_SAMESITE_COOKIE_NONE);
152+
153+
ck_assert_ptr_nonnull(oidc_cmd_cookie_same_site_session_set(cmd, NULL, "InvalidValue", NULL, NULL));
154+
155+
ck_assert_ptr_null(oidc_cmd_cookie_same_site_session_set(cmd, NULL, "Strict", "None", NULL));
156+
ck_assert_int_eq(oidc_cfg_cookie_same_site_session_get(cfg), OIDC_SAMESITE_COOKIE_STRICT);
157+
ck_assert_int_eq(oidc_cfg_cookie_same_site_state_get(cfg), OIDC_SAMESITE_COOKIE_NONE);
158+
ck_assert_int_eq(oidc_cfg_cookie_same_site_discovery_csrf_get(cfg), OIDC_SAMESITE_COOKIE_STRICT);
159+
160+
ck_assert_ptr_null(oidc_cmd_cookie_same_site_session_set(cmd, NULL, "Strict", "None", "Lax"));
161+
ck_assert_int_eq(oidc_cfg_cookie_same_site_session_get(cfg), OIDC_SAMESITE_COOKIE_STRICT);
162+
ck_assert_int_eq(oidc_cfg_cookie_same_site_state_get(cfg), OIDC_SAMESITE_COOKIE_NONE);
163+
ck_assert_int_eq(oidc_cfg_cookie_same_site_discovery_csrf_get(cfg), OIDC_SAMESITE_COOKIE_LAX);
164+
165+
ck_assert_ptr_null(oidc_cmd_cookie_same_site_session_set(cmd, NULL, "Lax", "Lax", "None"));
166+
ck_assert_int_eq(oidc_cfg_cookie_same_site_session_get(cfg), OIDC_SAMESITE_COOKIE_LAX);
167+
ck_assert_int_eq(oidc_cfg_cookie_same_site_state_get(cfg), OIDC_SAMESITE_COOKIE_LAX);
168+
ck_assert_int_eq(oidc_cfg_cookie_same_site_discovery_csrf_get(cfg), OIDC_SAMESITE_COOKIE_NONE);
169+
}
170+
END_TEST
171+
128172
int main(void) {
129173
TCase *core = tcase_create("core");
130174
tcase_add_checked_fixture(core, oidc_test_setup, oidc_test_teardown);
@@ -133,6 +177,7 @@ int main(void) {
133177
#ifdef USE_MEMCACHE
134178
tcase_add_test(core, test_cfg_cache_connections_ttl);
135179
#endif
180+
tcase_add_test(core, test_cmd_cookie_same_site);
136181

137182
Suite *s = suite_create("cfg");
138183
suite_add_tcase(s, core);

0 commit comments

Comments
 (0)