Hi all,

I have encounter this samesite issue as well for our 5.3.x CAS servers, and 
I come up with an ugly custom fix, I am sharing here if anyone need quick 
fix.

Since I manage multiple SPs for our CAS, and one SP with a different domain 
use CAS inside an iframe which trigger this issue.

There are multiple issue I encounter:
- *Spring issue*: CAS are using Spring, but seems the samesite issue still 
not fix on Spring end, so it is really hard to make clean fix 
- *Compatbility issue*: If you just enabled the samesite = None, it will 
break some recent version of Mac, which is really not ideal.

What we done to fix it:

*Spring issue:*

At least on last time I research, seems like Spring are still taking some 
time to fix this issue, so we will need to code it ourselves.

For that, we just use generateHeader logic from: 
https://github.com/apache/tomcat/blob/master/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java

And implement our  own TGCCookieRetrievingCookieGenerator.


*Compatibility issue:*

We follows this: 
https://www.chromium.org/updates/same-site/incompatible-clients

And change it to Java.

We have tested enough device before making the deployment, and seems fairly 
stable no one complain about compatibility issue:

*SamesiteCookieChecker.java*
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Follows the snippet in 
https://www.chromium.org/updates/same-site/incompatible-clients 
 * and convert it to Java compatible
 * 
 *
 */
public class SamesiteCookieChecker {

// Copyright 2019 Google LLC.
// SPDX-License-Identifier: Apache-2.0

// Don’t send `SameSite=None` to known incompatible clients.

public boolean shouldSendSameSiteNone(String useragent) {
    return !isSameSiteNoneIncompatible(useragent);
}

// Classes of browsers known to be incompatible.

private boolean isSameSiteNoneIncompatible(String useragent) {
    return hasWebKitSameSiteBug(useragent) ||
           dropsUnrecognizedSameSiteCookies(useragent);
}

private boolean hasWebKitSameSiteBug(String useragent) {
    return isIosVersion(12, useragent) ||
           (isMacosxVersion(10, 14, useragent) &&
            (isSafari(useragent) || isMacEmbeddedBrowser(useragent)));
}

private boolean dropsUnrecognizedSameSiteCookies(String useragent) {
    if (isUcBrowser(useragent)){ 
        return !isUcBrowserVersionAtLeast(12, 13, 2, useragent);
    }
    return isChromiumBased(useragent) &&
           isChromiumVersionAtLeast(51, useragent) &&
           !isChromiumVersionAtLeast(67, useragent);
}

// Regex parsing of User-Agent string. (See note above!)

private boolean isIosVersion(int major, String useragent) {
String regex = "\\(iP.+; CPU .*OS (\\d+)[_\\d]*.*\\) AppleWebKit\\/";
    // Extract digits from first capturing group.
Matcher  m = Pattern.compile(regex).matcher(useragent);
if(!m.find()) {
return false;
}
//return useragent.regexMatch(regex)[0] == intToString(major);
return m.group(1).equals(String.valueOf(major));
}

private boolean isMacosxVersion(int major, int minor, String useragent) {
String regex = "\\(Macintosh;.*Mac OS X (\\d+)_(\\d+)[_\\d]*.*\\) 
AppleWebKit\\/";
    // Extract digits from first and second capturing groups.
Matcher  m = Pattern.compile(regex).matcher(useragent);
if(!m.find()) {
return false;
}
//     return (useragent.regexMatch(regex)[0] == intToString(major)) &&
//            (useragent.regexMatch(regex)[1] == intToString(minor));
return m.group(1).equals(String.valueOf(major)) &&
m.group(2).equals(String.valueOf(minor));
}

private boolean isSafari(String useragent) {
String safari_regex = "Version\\/.* Safari\\/";
//     return useragent.regexContains(safari_regex) &&
//            !isChromiumBased(useragent);
    return Pattern.compile(safari_regex).matcher(useragent).find() &&
           !isChromiumBased(useragent);
}

private boolean isMacEmbeddedBrowser(String useragent) {
String regex = "^Mozilla\\/[\\.\\d]+ \\(Macintosh;.*Mac OS X [_\\d]+\\) "
                     + "AppleWebKit\\/[\\.\\d]+ \\(KHTML, like Gecko\\)$";
    return Pattern.compile(regex).matcher(useragent).find();
}

private boolean isChromiumBased(String useragent) {
String regex = "Chrom(e|ium)";
return Pattern.compile(regex).matcher(useragent).find();
}

private boolean isChromiumVersionAtLeast(int major, String useragent) {
String regex = "Chrom[^ \\/]+\\/(\\d+)[\\.\\d]* ";
    // Extract digits from first capturing group.
Matcher  m = Pattern.compile(regex).matcher(useragent);
if(!m.find()) {
return false;
}
String version = m.group(1);
int intVersion;
try {  
intVersion =  Integer.parseInt(version);  
} catch(NumberFormatException nfe) {
return false;
}
return intVersion >= major;
    //int version = stringToInt(useragent.regexMatch(regex)[0]);
    //return version >= major;
}

private boolean isUcBrowser(String useragent) {
String regex = "UCBrowser\\/";
    return Pattern.compile(regex).matcher(useragent).find();
}

private boolean isUcBrowserVersionAtLeast(int major, int minor, int build, 
String useragent) {
String regex = "UCBrowser\\/(\\d+)\\.(\\d+)\\.(\\d+)[\\.\\d]* ";
Matcher  m = Pattern.compile(regex).matcher(useragent);
if(!m.find()) {
return false;
}
    // Extract digits from three capturing groups.
    int major_version;
    int minor_version;
    int build_version;
try {  
    major_version = Integer.parseInt(m.group(1));
    minor_version = Integer.parseInt(m.group(2));
    build_version = Integer.parseInt(m.group(3));
} catch(NumberFormatException nfe) {
return false;
}
    if (major_version != major) {
        return major_version > major;
    }
    if (minor_version != minor) {
        return minor_version > minor;
    }
    return build_version >= build;
}
}

=============================================
Using the above I am managed to hot fix this samesite=none issue. Hopefully 
Spring will be able to fix this later down the timeline, so no need code it 
like this outselves.


Cheers!
- Andy









-- 
- Website: https://apereo.github.io/cas
- Gitter Chatroom: https://gitter.im/apereo/cas
- List Guidelines: https://goo.gl/1VRrw7
- Contributions: https://goo.gl/mh7qDG
--- 
You received this message because you are subscribed to the Google Groups "CAS 
Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/a/apereo.org/d/msgid/cas-user/18adee3b-98c8-4605-8bf4-5d4069f1dc1a%40apereo.org.

Reply via email to