IdP SameSite Testing

IdP SameSite Testing

If you're looking for concise conclusions about the impact of SameSite on the Shibboleth software, please refer to the relevant topics under Productionalization in each software product's documentation space. This page is the underlying research and testing summary developed by the project over the last several months and used to inform project decision making. It's more technical and not organized into an easily digestible form.



Jira Issue

key summary type created updated due assignee reporter priority status resolution
Loading...
Refresh

Important

This work has been triggered by the Google IETF draft 'Incrementally Better Cookies' [6], which aims to default all cookies without a same-site flag to SameSite=Lax, and  requiring SameSite=None cookies to be sent over secure transport (HTTPS). This will become the default in Chrome 80, which will be released approximately February 2020.  

Introduction



The Same-site cookie atribute is a IETF draft written by Google Inc. [1][2]which, at its most strict, instructs the user-agent not to send (attach) a SameSite cookie during a cross site HTTP request. The principal aim of which is to help prevent forms of cross site request forgery that ‘ride’ ambient authority session cookies.

A cross site request is, abstractly (see appendix A for the draft algorithmic definition), one where the top level site (typically that shown in an address bar) changes during navigation.

There are three values for the same-site cookie attribute:

  • Strict - Only attach cookies for ‘same-site’ requests.

  • Lax - Send cookies for ‘same-site’ requests, along with ‘cross-site’ top level navigations using safe HTTP methods e.g. (GET HEAD OPTIONS TRACE).

  • None - send cookies for all ‘same-site’ and ‘cross-site’ requests.

Note

Note, there is an updated draft [3] which defines two new SameSite values ‘FirstPartyLax’ and ‘FirstPartyStrict’, which are used in relation to ‘First-Party sets’ (groupings of registered domains to a single controlled entity). These values are not used here, and will be discussed in follow up implementation work - although at first glance, this seems unlikely to be used in a dynamic SSO federation.

Chrome 76 and onwards contain a flag to enable the treatment of cookies without a SameSite attribute to be SameSite=Lax. This will become the default in Chrome 80 [4], which has an approximate release date of February 2020 - see the section below for an overview of browser support. The aim of this document is to test the affects of such change on the IdP. Our immediate concern is, if the session cookies used by the IdP (depending on configuration) e.g. JSESSIONID, or shib_idp_session, do not specify the SameSite attribute - and are therefore defaulted to SameSite=Lax - and are being used in a cross-site POST request from an SP to the IdP, will it break either the IdP and or single-sign-on as potentially the session cookies will not be sent.

Further work will investigate a Proof of Concept servlet filter for munging appropriate IdP session cookies in order to set their SameSite attribute to None - thus maintaining their current behaviour. This is only necessary because the Java Servlet Specification v3.0 or v4.0 does not cater for the SameSite attribute, and it can not be set through the Java Cookie API.

SameSite Browser Support



The table below shows same-site cookie attribute compatibility amongst desktop browsers (see [5] for a complete list including mobile variants). It also includes an attempt to determine current/future browser support for IETF draft 'Incrementally Better Cookies '[6]. That is, defaulting same-site unset cookies to SameSite=Lax, and requiring SameSite=None cookies to be sent over secure transport (HTTPS).

The table will be updated as and when information becomes available.

Browser

SameSite Support

Can enable SameSite Lax By Default

Can enable SameSite None requires Secure by default

SameSite Lax enabled in browser by default

SameSite None requires secure enabled in browser by default

Browser

SameSite Support

Can enable SameSite Lax By Default

Can enable SameSite None requires Secure by default

SameSite Lax enabled in browser by default

SameSite None requires secure enabled in browser by default

Firefox desktop

v60 onwards

in advanced setting/preferences (about:config) from v69

in advanced setting/preferences (about:config) from v69

unknown but likely to happen

unknown but likely to happe

Chrome desktop

v51 onward

in experimental features (chrome://flags) from v76

in experimental features (chrome://flags) from v76

Stable Chrome 80 (aprox. Feb 4th 2020,https://chromiumdash.appspot.com/schedule). Although likely to be the default in Chrome Beta 79.

Stable Chrome 80 (aprox. Feb 4th 2020,https://chromiumdash.appspot.com/schedule).Although likely to be the default in Chrome Beta 79.

Safari desktop

v12 onward**

unknown

unknown

unknown

unknown

Opera desktop

v39 onward

in experiments (opera://flags/) from 63 onward

in experiments (opera://flags/) from 63 onward

likely to follow chrome as chromium/blink based.

likely to follow chrome as chromium/blink based.

Edge

v16 onward

possible in Edge builds based on chromium 76 onward (2019). Not sure about older EdgeHTML engines. In experimental features (edge://flags)

possible in Edge builds based on chromium 76 onward (2019). Not sure about older EdgeHTML engines - looks like that will NOT happen in IE or Edge <v18. In experimental features (edge://flags)

likely to follow chrome as in 2019 Edge became chromium/blink based.

likely to follow chrome as in 2019 Edge became chromium/blink based.

** Safari Issue

Webkit based browsers on Mac (safari) and iOS (safair, chome, firefox etc)  are currently affected by a bug that treats SameSite=None or SameSite=nonesense cookies as SameSite=Strict (https://bugs.webkit.org/show_bug.cgi?id=198181). We believe the fix for this will only take effect from MacOS 10.15 and iOS 13. Consequently, any attempt to maintain the current functional behaviour of cookies by setting SameSite=None on unpatched versions of Webkit will break SSO.

This bug also affects older Chrome and Android browsers.

Firefox issue

To compound matters, Firefox has a bug filed (https://bugzilla.mozilla.org/show_bug.cgi?id=1465402) that suggests they may consider the ability to set even Lax cookies in the middle of SP→ IdP → IdP redirect chains to be a bug. If they decide to "fix" this non-bug, it will cause the current default behavior to stop functioning correctly at all with Firefox because the JSESSIONID cookie set upon initial contact to the IdP will be ignored, and the follow-on request will trigger a flow exception error. This would make "doing nothing" a non-option and create a hopeless situation without ugly workarounds to accomodate three different non-overlapping modes of behavior.

Testing

Testing Update

The testing methodology has been updated. All previous tests were run with the IdP configured to allow the storage of sessions in client side HTML local storage (idp.storage.htmlLocalStorage=true). This has the effect of enabling SSO when using the HTTP-POST binding even when cookies are defaulted to SameSite=Lax, or even when using server side session storage. Without it, SSO will fail when initiated using the HTTP-POST binding from a cross-site SP, and the user will be always presented with the login page. 

To test the affects of various SameSite settings, the following setup will be used:

  • Chrome Canary 78.0.3885.0 (Official Build) canary (64-bit), with #same-site-by-default-cookies set to enabled. This is to mimic what will become the default behaviour in Chrome 80 onward.

  • The IdP running in eclipse using the Java idp-testbed project.

    • Using idp-jetty-base with Jetty v9.3.

    • A new SAML2Controller InitSSO POST method/endpoint. This overwrites the destination URL with localhost, ignoring the baseURL of the servlet request.

  • A modified hosts file, that points the hostname of shibtest.com to 127.0.0.1 (localhost)

    • The SAML2Controller can then be accessed on a different top-level site than the IdP - to mimic a cross site request.

  • The standard IdP Password authentication flow.



Using Client Side Session Storage, allowing HTML local storage.

The IdP is configured here to use client side session storage with, importantly, idp.storage.htmlLocalStorage set too true. The table below shows the results of various tests using different SAML2.0 bindings or initiators. The shib_idp_session_ss is less relevant, and could use local storage if supported by the browser with similar same effect.

Of note, this does not test the affect of any SP cookies sent cross-site from the IdP.



No

Test

SameSite Value

Results

Browser

IdP Working

SSO Working

Expected Result

No

Test

SameSite Value

Results

Browser

IdP Working

SSO Working

Expected Result

1

GET - Unsolicited SSO Cross Site

JSESSIONID=Strict, shib_idp_session=Lax, shib_idp_session_ss=Lax

JSESSIONID Cookie is not sent cross site. The flow can not be resumed during the GET-REDIRECT-GET for the client-storage-read view-state. That is, the JSESSIONID is SET on response from the inital GET request, but is not sent cross-site on the REDIRECT GET request, hence webflow can not resume the conversation

Chrome 78.0.3888.0 (Official Build) canary (64-bit)

No

No

Yes

2

GET - Unsolicited SSO Cross Site



JSESSIONID=Lax, shib_idp_session=Lax, shib_idp_session_ss=Lax

All cookies are sent cross site.

Chrome 78.0.3888.0 (Official Build) canary (64-bit)

Yes

Yes

Yes

3

GET - Unsolicited SSO Cross Site

Not Set (defaults to Lax)

All cookies are sent cross site. Chrome is treating all cookies not set with SameSite as Lax, as enabled by the #same-site-by-default-cookies chrome flag

Chrome 78.0.3888.0 (Official Build) canary (64-bit)

Yes

Yes

Yes

4

POST - SAML 2.0 Post Binding

JSESSIONID=Strict, shib_idp_session=Lax,shib_idp_session_ss=Lax

The IdP goes in search of the session from HTML local storage (because it is enabled), hence webflow POST-REDIRECT-GET cycle on the initial client-storage-read view, JSESSIONID is SET on REDIRECT, but not sent on GET, hence the flow can not be resumed from the client-storage-read view

Chrome 78.0.3888.0 (Official Build) canary (64-bit)

No

No

Yes

5

POST - SAML 2.0 Post Binding

JSESSIONID=Lax, shib_idp_session=Lax, shib_idp_session_ss=Lax

The IdP goes in search of the session from HTML local storage (because it is enabled), hence webflow performs a POST-REDIRECT-GET cycle on the initial client-storage-read view, JSESSIONID is SET on REDIRECT, and is sent along with the shib_idp_session and shib_idp_session_ss on GET, hence the flow can be resumed, the shib_idp_session_ss is reloaded, matched to the shib_idp_session and SSO performed

Chrome 78.0.3888.0 (Official Build) canary (64-bit)

Yes

Yes

No, expecting to fail because of the initial POST request. See the detailed description in section [SameSite Lax POST flow] below

6



POST - SAML 2.0 Post Binding

Not Set (defaults to Lax)

Chrome is treating all cookies not set with SameSite as Lax, as enabled by the #same-site-by-default-cookies chrome flag. The IdP goes in search of the session from HTML local storage (because it is enabled), hence webflow POST-REDIRECT-GET cycle on the initial client-storage-read view, JSESSIONID is set on REDIRECT, and is sent along with the shib_idp_session and shib_idp_session_ss on GET, hence the flow can be resumed, the shib_idp_session_ss is reloaded, matched to the shib_idp_session and SSO performed. Although this is not consistent.

Chrome 78.0.3888.0 (Official Build) canary (64-bit)

Yes

Yes/No

No, expecting to fail because of the initial POST request. See the note below, behaviour is not consistent

7

POST - SAML 2.0 Post Binding

JSESSIONID=Lax, shib_idp_session=None, shib_idp_session_ss=Lax

A new JSESSIONID is set during the initial Webflow POST-REDIRECT-GET cycle on the initial client-storage-read view, the shib_idp_session is sent with every request, the shib_idp_session_ss is sent on the final GET request. SSO is performed

Chrome 78.0.3888.0 (Official Build) canary (64-bit)

Yes

Yes

Yes, all requests carry the shib_idp_session required for SSO, the initial POST-REDIRECT-GET cycle creates and then sends the JSESSIONID to progress the webflow conversation

8

GET - Redirect

JSESSIONID=Lax, shib_idp_session=Lax,shib_idp_session_ss=Lax

All cookies are sent cross-site

Chrome 78.0.3888.0 (Official Build) canary (64-bit)

Yes

Yes

Yes

9

GET - Redirect

Not Set (defaults to Lax)

All cookies are sent cross-site

Chrome 78.0.3888.0 (Official Build) canary (64-bit)

Yes

Yes

Yes



** This is only the case if the Client Session Storage Service beans are removed from the shibboleth.ClientStorageServices list. Otherwise, the PopulateClientStorageLoadContext will load session information from the client using the client-storage-read view-state, which will then send the shib_idp_session cookie same-origin after that view-state has posted back to the IdP.



IMPORTANT:
It appears that current versions of Chrome are treating defaulted (SameSite not set) cookies as SameSite Lax + POST for a period of 2 minutes from when they are set, then SameSite Lax thereafter Issue 990439 - chromium - An open-source project to help move the web forward. - Monorail. Within this window, the the IdP will operate normally, as if there is no SameSite restriction. Otherwise, there are two general possibities:

  1. All IdP session cookies which where set more than 2 minutes ago are treated as Lax. This then gives the same result as test 5 above, and the description in the section [SameSite Lax POST flow].

  2. Different combinations of JSESSIONID, shib_idp_session or shib_idp_session_SS are inside or outside of the 2 minute window. This leads to different types of behaviour; most commonly, as JSESSIONID is nearly (always) set first, the following would be true

    1. JSESSIONID=Lax+POST, shib_idp_session=Lax, shib_idp_session_ss=Lax. The JSESSIONID is sent cross-site with the post request but the shib_idp_session and shib_idp_session_ss are not. The storage services can be pulled out of the given session referenced by the JESSIONID, and hence client-storage-read is not required to reload it. The flow continues without the POST-REDIRECT-GET cycle of a view-state, hence the shib_idp_session cookie is not sent and the previous authentication result can not be retrieved from the IdPSession. As a result, the username and password login view is presented - thus breaking SSO.

SameSite Lax, POST flow, with client side session storage and HTML local storage option enabled

The following outlines the network interactions with the IdP for a POST SAML SSO request. The user has previously authenticated using the standard Password flow, and in so doing obtained shib_idp_session and JSESSIONID cookies. The IdP is using client side session storage, either as a cookie or in HTML local storage.

SO = Same-origin request.
CS = Cross-site request.
sp/SAML2/InitSSO-CS/POST = is a new controller endpoint that overrides destination address with ‘localhost’ to mimic a cross-site request.

  1. user-agent top-level site is https://shibtest.com:8443.

  2. (SO)(GET) user-agent navigates to https://shibtest.com:8443/sp/SAML2/InitSSO-CS/POST. Which is a same-origin request to initate a SAML 2 AuthN Request.

  3. BEGIN SAML AUTHENTICATION REQUEST ------

  4. (CS)(POST) The shibtest.com sp/SAML2/InitSSO-CS/POST controller performs a cross-site POST SAML authentication request to the IdP at https://localhost:8443/idp/profile/SAML2/POST/SSO.

    1. SameSite is LAX, hence cookies for the localhost domain are NOT sent cross-site e.g. any existing JSESSIONID, shib_idp_session or if present shib_idp_session_ss cookies are not sent.

    2. The IdP processes the SAML request, is unable to load the client storage context as the JESSIONID was not sent, and the new one the container issues does not link to a session that already exists. Hence it goes in search of the session from HTML local storage (because it is enabled), and proceeds to the LocalStorageRead view-state, commits a redirect response (https://localhost:8443/idp/profile/SAML2/POST/SSO?execution=e1s1) to the user-agent, and issues a new JSESSIONID.

    3. Note, the user-agent still has a top-level site of https://shibtest.com:8443.

  1. (CS)(GET) The user-agent responds to the redirect with a cross-site GET request to https://localhost:8443/idp/profile/SAML2/POST/SSO?execution=e1s1. Which then displays the client-storage-read.vm page.

    1. Webflow is using a POST-REDIRECT-GET strategy*. This cycle is happening cross-site, but the final GET request allows Lax SameSite cookies to be sent. Hence, the new JSESSIONID obtained in the inital POST-REDIRECT response is sent with the final GET request and the flow can resume. Note, the shib_idp_session cookie is sent with the final GET cross-site request but that is not strictly that important at this stage.

    2. From here any subsequent requests occur same-origin so cookies are always sent.

  1. (SO)(POST) The user-agent then POSTS form data from the client-storage-read view back to the IdP. This is a same-origin request, and contains all required cookies and session information.

    1. The flow continues and the shib_idp_sesison cookie is used to find a previous IdPSession from the loaded (from cookie or local storage) shib_idp_session_ss storage record during the PopulateSessionContext action using the StorageBackedSessionManager.

    2. The ExtractActiveAuthenticationResults action then extracts the AuthenticationResult from the IdpSession and, providing certain criteria are satisfied, enables SSO.

[*][By default when a flow enters a view state, it executes a client-side redirect before rendering the view]

Using Client Side Session Storage and Disabling HTML Local Storage.

Here we test again, this time disabling the IdPs ability to use HTML local storage to store session information, instead only using cookies e.g. setting idp.storage.htmlLocalStorage to false.



No

Test

SameSite Value

Results

Browser

IdP working

SSO Working

Expected Result

No

Test

SameSite Value

Results

Browser

IdP working

SSO Working

Expected Result

10

POST - SAML 2.0 Post Binding

JSESSIONID=Strict, shib_idp_session=Lax,shib_idp_session_ss=Lax

The IdP does not receive the JSESSIONID cross-site, it can not resume an IdPSession, hence it tries to load the DisplayUsernamePasswordPage (login) page. Webflow performs a POST-REDIRECT-GET cycle to render the login page, but because it can not resume the flow on the final GET request (because the JSESSIONID is still not sent cross-site), Webflow is unable to resume the flow and throws an error.

Firefox 72.0.1 with sameSite default enabled

No

No

Yes

11

POST - SAML 2.0 Post Binding

JSESSIONID=Lax, shib_idp_session=Lax, shib_idp_session_ss=Lax

No cookies are sent cross-site, however the IdP no longer goes in search of the session from HTML local storage on the browser, and hence does not render the client-storage-read view. As a result, there are no same-site requests to the IdP where the the shib_idp_session_ss cookie could be sent before the IdP tries to load the SSO session. Therefore, left without any SSO session information, the IdP renders the login page. 

Firefox 72.0.1 with sameSite default enabled

Yes

No

Yes, was expected a similar result to test 5. 

12

POST - SAML 2.0 Post Binding

Not Set (defaults to Lax). 

Same results as 11. 

Firefox 72.0.1 with sameSite default enabled

Yes

No

No, expecting to fail because of the initial POST request. See the note below, behaviour is not consistent



Using Server Side Session Storage and Enabling/Disabling HTML Local Storage. 



Four different POST requests where again tested, this time using server side session storage. The hypothesis being, under the following conditions, SSO will break:

  1. The IdP session cookies are treated as SameSite=Lax.

  2. The entire SAML2 SSO flow on the IdP is completed from the initial cross-site POST request from the SP - because the client-storage-read view is not required as client side storage is not used.

No

Test

SameSite Value

Results

Browser

IdP

working

SSO Working

Expected Result

No

Test

SameSite Value

Results

Browser

IdP

working

SSO Working

Expected Result

13

POST - SAML 2.0 Post Binding (Server Side Session Storage). Client storage services list  not empty. HTML local storage set too true.

JSESSIONID=Lax, shib_idp_session=Lax

No cookies sent cross-site, but the client-storage-read view is rendered because the idp.storage.htmlLocalStorage option is set to true, and the shib_idp_session cookie is sent on subsequent same-origin requests from that view. Hence, the shib_idp_session can be used to retrieve a server side IdPSession and SSO occurs. 

Chrome 78.0.3888.0 (Official Build) canary (64-bit)

Yes

Yes

No

14

POST - SAML 2.0 Post Binding (Server Side Session Storage).  ClientStorageServices list empty. HTML local storage set too true.

JSESSIONID=Lax, shib_idp_session=Lax