Skip to content

Commit

Permalink
Set "SameSite=None" attribute on cookies to allow CORS requests
Browse files Browse the repository at this point in the history
Addresses RM-34203
  • Loading branch information
pdo-axelor committed Feb 8, 2021
1 parent b47f48c commit 5e896b7
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 32 deletions.
42 changes: 17 additions & 25 deletions axelor-core/src/main/java/com/axelor/auth/AuthFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.axelor.events.LoginRedirectException;
import com.axelor.events.PostLogin;
import com.axelor.events.PreLogin;
import com.axelor.inject.Beans;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.UncheckedIOException;
Expand Down Expand Up @@ -55,8 +54,6 @@ public class AuthFilter extends FormAuthenticationFilter {
@Inject private Event<PreLogin> preLogin;
@Inject private Event<PostLogin> postLogin;

private static final String SESSION_COOKIE_NAME = "JSESSIONID";

@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response)
throws Exception {
Expand Down Expand Up @@ -110,7 +107,7 @@ protected boolean isLoginRequest(ServletRequest request, ServletResponse respons
public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException {

setSessionSameSiteNone((HttpServletRequest) request, (HttpServletResponse) response);
setSameSiteNone((HttpServletRequest) request, (HttpServletResponse) response);

// tomcat 7.0.67 doesn't redirect with / if root request is sent without slash
// see RM-4500 for more details
Expand Down Expand Up @@ -165,45 +162,40 @@ protected boolean onLoginSuccess(
return super.onLoginSuccess(token, subject, request, response);
}

public static void changeSessionId() {
final HttpServletRequest request = Beans.get(HttpServletRequest.class);
request.changeSessionId();
if (request.isSecure()) {
setSessionSameSiteNone(Beans.get(HttpServletResponse.class));
}
}

private static void changeSessionId(HttpServletRequest request, HttpServletResponse response) {
request.changeSessionId();
setSessionSameSiteNone(request, response);
setSameSiteNone(request, response);
}

public static void setSessionSameSiteNone(
HttpServletRequest request, HttpServletResponse response) {
if (request.isSecure()) {
setSessionSameSiteNone(response);
public static void setSameSiteNone(HttpServletRequest request, HttpServletResponse response) {
if (!request.isSecure() && !"https".equalsIgnoreCase(getProto(request))) {
return;
}
}

private static void setSessionSameSiteNone(HttpServletResponse response) {
final Subject subject = SecurityUtils.getSubject();
subject.getSession();

final Collection<String> headers = response.getHeaders(HttpHeaders.SET_COOKIE);
final Iterator<String> it = headers.iterator();
if (it.hasNext()) {
addCookieHeader(it.next(), response::setHeader);
addSameSiteCookieHeader(response::setHeader, it.next());
while (it.hasNext()) {
addCookieHeader(it.next(), response::addHeader);
addSameSiteCookieHeader(response::addHeader, it.next());
}
}
}

private static void addCookieHeader(String header, BiConsumer<String, String> headerAdder) {
if (header.startsWith(SESSION_COOKIE_NAME)) {
header = String.format("%s; %s", header, "SameSite=None");
private static String getProto(HttpServletRequest request) {
final String proto = request.getHeader("X-Forwarded-Proto");
return StringUtils.isBlank(proto) ? request.getScheme() : proto;
}

private static void addSameSiteCookieHeader(BiConsumer<String, String> adder, String header) {
String extraAttrs = "; SameSite=None";
if (header.indexOf("; Secure") < 0) {
extraAttrs += "; Secure";
}
headerAdder.accept(HttpHeaders.SET_COOKIE, header);
adder.accept(HttpHeaders.SET_COOKIE, header + extraAttrs);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@
import com.axelor.event.Event;
import com.axelor.event.NamedLiteral;
import com.axelor.events.PostLogin;
import com.axelor.inject.Beans;
import java.lang.invoke.MethodHandles;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationListener;
Expand All @@ -47,7 +50,10 @@ public void onSuccess(AuthenticationToken token, AuthenticationInfo info) {
final User user = ((UserAuthenticationInfo) info).getUser();

if (user != null) {
AuthFilter.changeSessionId();
final HttpServletRequest request = Beans.get(HttpServletRequest.class);
final HttpServletResponse response = Beans.get(HttpServletResponse.class);
request.changeSessionId();
AuthFilter.setSameSiteNone(request, response);
firePostLoginSuccess(token, user);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ public Object perform(
Boolean inputDestroySession,
Boolean inputCentralLogout) {

AuthFilter.setSessionSameSiteNone(context.getRequest(), context.getResponse());
AuthFilter.setSameSiteNone(context.getRequest(), context.getResponse());

// Destroy web session.
return super.perform(
Expand Down Expand Up @@ -337,7 +337,7 @@ public Object perform(
Boolean inputRenewSession,
String client) {

AuthFilter.setSessionSameSiteNone(context.getRequest(), context.getResponse());
AuthFilter.setSameSiteNone(context.getRequest(), context.getResponse());

try {
context.getRequest().setCharacterEncoding("UTF-8");
Expand Down Expand Up @@ -423,7 +423,7 @@ public Object perform(
Boolean inputMultiProfile,
Object... parameters) {

AuthFilter.setSessionSameSiteNone(context.getRequest(), context.getResponse());
AuthFilter.setSameSiteNone(context.getRequest(), context.getResponse());

return super.perform(
context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,7 @@ public static class FormFilter extends AnonymousFilter {
@Override
protected boolean onPreHandle(
ServletRequest request, ServletResponse response, Object mappedValue) {
AuthFilter.setSessionSameSiteNone(
(HttpServletRequest) request, (HttpServletResponse) response);
AuthFilter.setSameSiteNone((HttpServletRequest) request, (HttpServletResponse) response);
return super.onPreHandle(request, response, mappedValue);
}
}
Expand Down
2 changes: 1 addition & 1 deletion changelogs/unreleased/fix-same-site-none-secure-cookie.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
title: Set "SameSite=None" attribute to session cookie to allow CORS requests
title: Set "SameSite=None" attribute on cookies to allow CORS requests
type: fix

0 comments on commit 5e896b7

Please sign in to comment.