mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-08 20:12:23 +00:00
tweak shiro to get samesite attribute on session cookie
bug 5435
This commit is contained in:
1 parent
e94350b960
commit
7fab76e128
1 file changed
+178
@@ -1,12 +1,30 @@
|
||||
package com.sap.sse.security;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.shiro.session.InvalidSessionException;
|
||||
import org.apache.shiro.session.Session;
|
||||
import org.apache.shiro.session.SessionException;
|
||||
import org.apache.shiro.session.UnknownSessionException;
|
||||
import org.apache.shiro.session.mgt.SessionContext;
|
||||
import org.apache.shiro.session.mgt.SessionKey;
|
||||
import org.apache.shiro.util.StringUtils;
|
||||
import org.apache.shiro.web.servlet.Cookie;
|
||||
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
|
||||
import org.apache.shiro.web.servlet.SimpleCookie;
|
||||
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
|
||||
import org.apache.shiro.web.util.WebUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.impl.MillisecondsDurationImpl;
|
||||
@@ -25,6 +43,7 @@ import com.sap.sse.util.TimerWithRunnable;
|
||||
*
|
||||
*/
|
||||
public class SecurityWebSessionManager extends DefaultWebSessionManager {
|
||||
private static final Logger log = LoggerFactory.getLogger(SecurityWebSessionManager.class);
|
||||
private static final TimerWithRunnable timer = new TimerWithRunnable("Timer delaying Session.touch() onChange(s) notifications", /* isDaemon */ true);
|
||||
|
||||
private static final Duration MAX_DURATION_ASSUMED_FOR_MESSAGE_DELIVERY = Duration.ONE_SECOND.times(30);
|
||||
@@ -97,4 +116,163 @@ public class SecurityWebSessionManager extends DefaultWebSessionManager {
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the Session's ID, usually as a Cookie, to associate with future requests.
|
||||
*
|
||||
* @param session the session that was just {@link #createSession created}.
|
||||
*/
|
||||
@Override
|
||||
protected void onStart(Session session, SessionContext context) {
|
||||
//super.onStart(session, context);
|
||||
|
||||
if (!WebUtils.isHttp(context)) {
|
||||
log.debug("SessionContext argument is not HTTP compatible or does not have an HTTP request/response " +
|
||||
"pair. No session ID cookie will be set.");
|
||||
return;
|
||||
|
||||
}
|
||||
HttpServletRequest request = WebUtils.getHttpRequest(context);
|
||||
HttpServletResponse response = WebUtils.getHttpResponse(context);
|
||||
|
||||
if (isSessionIdCookieEnabled()) {
|
||||
Serializable sessionId = session.getId();
|
||||
storeSessionId(sessionId, request, response);
|
||||
} else {
|
||||
log.debug("Session ID cookie is disabled. No cookie has been set for new session with id {}", session.getId());
|
||||
}
|
||||
|
||||
request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
|
||||
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
|
||||
}
|
||||
|
||||
private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
|
||||
if (currentId == null) {
|
||||
String msg = "sessionId cannot be null when persisting for subsequent requests.";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
Cookie template = getSessionIdCookie();
|
||||
Cookie cookie = new SamesiteCookie(template);
|
||||
String idString = currentId.toString();
|
||||
cookie.setValue(idString);
|
||||
cookie.setSecure(true);
|
||||
cookie.saveTo(request, response);
|
||||
log.trace("Set session ID cookie for session with id {}", idString);
|
||||
}
|
||||
|
||||
|
||||
private static class SamesiteCookie extends SimpleCookie {
|
||||
|
||||
public SamesiteCookie(Cookie template) {
|
||||
super(template);
|
||||
}
|
||||
|
||||
protected String buildHeaderValue(String name, String value, String comment, String domain, String path,
|
||||
int maxAge, int version, boolean secure, boolean httpOnly) {
|
||||
|
||||
if (!StringUtils.hasText(name)) {
|
||||
throw new IllegalStateException("Cookie name cannot be null/empty.");
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(name).append(NAME_VALUE_DELIMITER);
|
||||
|
||||
if (StringUtils.hasText(value)) {
|
||||
sb.append(value);
|
||||
}
|
||||
|
||||
appendComment(sb, comment);
|
||||
appendDomain(sb, domain);
|
||||
appendPath(sb, path);
|
||||
appendExpires(sb, maxAge);
|
||||
appendVersion(sb, version);
|
||||
appendSamesite(sb,"None");
|
||||
appendSecure(sb, secure);
|
||||
appendHttpOnly(sb, httpOnly);
|
||||
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
private void appendSamesite(StringBuilder sb, String value) {
|
||||
if (StringUtils.hasText(value)) {
|
||||
sb.append(ATTRIBUTE_DELIMITER);
|
||||
sb.append("SameSite").append(NAME_VALUE_DELIMITER).append(value);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendComment(StringBuilder sb, String comment) {
|
||||
if (StringUtils.hasText(comment)) {
|
||||
sb.append(ATTRIBUTE_DELIMITER);
|
||||
sb.append(COMMENT_ATTRIBUTE_NAME).append(NAME_VALUE_DELIMITER).append(comment);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendDomain(StringBuilder sb, String domain) {
|
||||
if (StringUtils.hasText(domain)) {
|
||||
sb.append(ATTRIBUTE_DELIMITER);
|
||||
sb.append(DOMAIN_ATTRIBUTE_NAME).append(NAME_VALUE_DELIMITER).append(domain);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendPath(StringBuilder sb, String path) {
|
||||
if (StringUtils.hasText(path)) {
|
||||
sb.append(ATTRIBUTE_DELIMITER);
|
||||
sb.append(PATH_ATTRIBUTE_NAME).append(NAME_VALUE_DELIMITER).append(path);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendExpires(StringBuilder sb, int maxAge) {
|
||||
// if maxAge is negative, cookie should should expire when browser closes
|
||||
// Don't write the maxAge cookie value if it's negative - at least on Firefox it'll cause the
|
||||
// cookie to be deleted immediately
|
||||
// Write the expires header used by older browsers, but may be unnecessary
|
||||
// and it is not by the spec, see http://www.faqs.org/rfcs/rfc2965.html
|
||||
// TODO consider completely removing the following
|
||||
if (maxAge >= 0) {
|
||||
sb.append(ATTRIBUTE_DELIMITER);
|
||||
sb.append(MAXAGE_ATTRIBUTE_NAME).append(NAME_VALUE_DELIMITER).append(maxAge);
|
||||
sb.append(ATTRIBUTE_DELIMITER);
|
||||
Date expires;
|
||||
if (maxAge == 0) {
|
||||
//delete the cookie by specifying a time in the past (1 day ago):
|
||||
expires = new Date(System.currentTimeMillis() - DAY_MILLIS);
|
||||
} else {
|
||||
//Value is in seconds. So take 'now' and add that many seconds, and that's our expiration date:
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.add(Calendar.SECOND, maxAge);
|
||||
expires = cal.getTime();
|
||||
}
|
||||
String formatted = toCookieDate(expires);
|
||||
sb.append(EXPIRES_ATTRIBUTE_NAME).append(NAME_VALUE_DELIMITER).append(formatted);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendVersion(StringBuilder sb, int version) {
|
||||
if (version > DEFAULT_VERSION) {
|
||||
sb.append(ATTRIBUTE_DELIMITER);
|
||||
sb.append(VERSION_ATTRIBUTE_NAME).append(NAME_VALUE_DELIMITER).append(version);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendSecure(StringBuilder sb, boolean secure) {
|
||||
if (secure) {
|
||||
sb.append(ATTRIBUTE_DELIMITER);
|
||||
sb.append(SECURE_ATTRIBUTE_NAME); //No value for this attribute
|
||||
}
|
||||
}
|
||||
|
||||
private void appendHttpOnly(StringBuilder sb, boolean httpOnly) {
|
||||
if (httpOnly) {
|
||||
sb.append(ATTRIBUTE_DELIMITER);
|
||||
sb.append(HTTP_ONLY_ATTRIBUTE_NAME); //No value for this attribute
|
||||
}
|
||||
}
|
||||
|
||||
private static String toCookieDate(Date date) {
|
||||
TimeZone tz = TimeZone.getTimeZone(GMT_TIME_ZONE_ID);
|
||||
DateFormat fmt = new SimpleDateFormat(COOKIE_DATE_FORMAT_STRING, Locale.US);
|
||||
fmt.setTimeZone(tz);
|
||||
return fmt.format(date);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user