The authn/SAML login flow in the Shibboleth Identity Provider supports the use of a separate SAML 2.0 Identity Provider to authenticate the subject, with the IdP acting as a SAML proxy. This flow provides native SAML support with additional features and flexibility without the need to deploy a separate SAML Service Provider implementation.
This is a review of how to employ a workaround in the Shibboleth Identity Provider to conditionally manage and control the SameSite cookie attribute, to prevent sporadic failures with this feature during the SAML POST back to the proxying Shibboleth IdP.
This tutorial specifically focuses on:
4.3.x
11
When the SAML proxying feature is deployed and turned on in the Shibboleth IdP, the POST back to the IdP from the proxied IdP may omit the necessary cookies to resume the flow, resulting in the “stale request” message. There are no alternatives but to get SameSite addressed if you use that feature with Chrome, Firefox, and other browsers that enforce this type of behavior.
Aside from the proxying case, the following deployment scenario results in the loss of SSO functionality (the user has to enter their credentials again).
The Shibboleth IdP includes a Java servlet filter class that can be deployed to work around Java’s lack of SameSite support and auto-add the attribute to cookies in various ways. It does have a generic extension point for attaching a condition that can be used for User-Agent testing.
To activate the filter, one needs the following properties in idp.properties
file:
idp.cookie.sameSite = None
idp.cookie.sameSiteCondition = My.SameSiteCondition
The My.SameSiteCondition
refers to a bean ID of a Predicate<ServletRequest>
component that would need to be defined in global.xml
file:
<bean id="My.SameSiteCondition" parent="shibboleth.Conditions.Scripted" factory-method="resourceScript"
p:returnOnError="true" p:hideExceptions="true" c:_0="javascript" c:_1="%{idp.home}/conf/my-samesite.js" />
The %{idp.home}/conf/my-samesite.js
executes a JSR-223 scriptlet against a ProfileRequestContext
to produce a true/false result. The script itself may be designed as such:
function minVersion(ua, browserName, version) {
var setSameSite = true;
var regexString = browserName + "/(\\d+)\\.";
var regex = new RegExp(regexString);
var match = ua.match(regex);
if (match) {
var major = parseInt(match[1]);
if (major < version) {
setSameSite = false;
}
}
return setSameSite;
}
var activate = true;
var logger = Java.type("org.slf4j.LoggerFactory").getLogger("My.SameSiteCondition");
try {
if (input != null) {
var UA = input.getHeader("User-Agent");
if (UA != null) {
logger.info('SameSite User-Agent: ' + UA);
if ((UA.contains("iPhone") || UA.contains("iPad") || UA.contains(" OS X "))
&& (UA.contains("Version/") && UA.contains("Safari/"))) {
activate = minVersion(UA, "Version", 15);
} else if (UA.contains("Firefox/")) {
activate = minVersion(UA, "Firefox", 60);
} else if (UA.contains("Opera/")) {
activate = minVersion(UA, "Opera", 39);
} else if (UA.contains("Chrome/")) {
activate = minVersion(UA, "Chrome", 51);
} else if (UA.contains("Chromium/")) {
activate = minVersion(UA, "Chromium", 51);
}
logger.debug('SameSite User-Agent: ' + activate);
}
}
}
catch (e) {
logger.error('SameSite User-Agent Error: ' + e);
}
return activate;
The returned outcome of the script is a boolean true/false
that is only set based on the type of browser and a minimum version that could support SameSite cookies. When the script returns true
, the IdP will set the SameSite attribute to None
, as specified via the idp.cookie.sameSite
property.
If you have questions about the contents and the topic of this blog post, or if you need additional guidance and support, feel free to send us a note and ask about consulting and support services.
I hope this review was of some help to you and I am sure that both this post as well as the functionality it attempts to explain can be improved in any number of ways. Please feel free to engage and contribute as best as you can.
Happy Coding,
Monday-Friday
9am-6pm, Central European Time
7am-1pm, U.S. Eastern Time
Monday-Friday
9am-6pm, Central European Time