|
@@ -16,6 +16,7 @@
|
|
|
|
|
|
package org.springframework.security.web.csrf;
|
|
package org.springframework.security.web.csrf;
|
|
|
|
|
|
|
|
+import java.lang.reflect.Method;
|
|
import java.util.UUID;
|
|
import java.util.UUID;
|
|
|
|
|
|
import javax.servlet.http.Cookie;
|
|
import javax.servlet.http.Cookie;
|
|
@@ -23,6 +24,7 @@ import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
|
import org.springframework.util.Assert;
|
|
import org.springframework.util.Assert;
|
|
|
|
+import org.springframework.util.ReflectionUtils;
|
|
import org.springframework.util.StringUtils;
|
|
import org.springframework.util.StringUtils;
|
|
import org.springframework.web.util.WebUtils;
|
|
import org.springframework.web.util.WebUtils;
|
|
|
|
|
|
@@ -47,6 +49,17 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
|
|
|
|
|
|
private String cookieName = DEFAULT_CSRF_COOKIE_NAME;
|
|
private String cookieName = DEFAULT_CSRF_COOKIE_NAME;
|
|
|
|
|
|
|
|
+ private final Method setHttpOnlyMethod;
|
|
|
|
+
|
|
|
|
+ private boolean cookieHttpOnly;
|
|
|
|
+
|
|
|
|
+ public CookieCsrfTokenRepository() {
|
|
|
|
+ this.setHttpOnlyMethod = ReflectionUtils.findMethod(Cookie.class, "setHttpOnly", boolean.class);
|
|
|
|
+ if (this.setHttpOnlyMethod != null) {
|
|
|
|
+ this.cookieHttpOnly = true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
@Override
|
|
@Override
|
|
public CsrfToken generateToken(HttpServletRequest request) {
|
|
public CsrfToken generateToken(HttpServletRequest request) {
|
|
return new DefaultCsrfToken(this.headerName, this.parameterName,
|
|
return new DefaultCsrfToken(this.headerName, this.parameterName,
|
|
@@ -66,6 +79,10 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
|
|
else {
|
|
else {
|
|
cookie.setMaxAge(-1);
|
|
cookie.setMaxAge(-1);
|
|
}
|
|
}
|
|
|
|
+ if (cookieHttpOnly && setHttpOnlyMethod != null) {
|
|
|
|
+ ReflectionUtils.invokeMethod(setHttpOnlyMethod, cookie, Boolean.TRUE);
|
|
|
|
+ }
|
|
|
|
+
|
|
response.addCookie(cookie);
|
|
response.addCookie(cookie);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -94,7 +111,7 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Sets the name of the HTTP header that should be used to provide the token
|
|
|
|
|
|
+ * Sets the name of the HTTP header that should be used to provide the token.
|
|
*
|
|
*
|
|
* @param headerName the name of the HTTP header that should be used to provide the
|
|
* @param headerName the name of the HTTP header that should be used to provide the
|
|
* token
|
|
* token
|
|
@@ -105,7 +122,7 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Sets the name of the cookie that the expected CSRF token is saved to and read from
|
|
|
|
|
|
+ * Sets the name of the cookie that the expected CSRF token is saved to and read from.
|
|
*
|
|
*
|
|
* @param cookieName the name of the cookie that the expected CSRF token is saved to
|
|
* @param cookieName the name of the cookie that the expected CSRF token is saved to
|
|
* and read from
|
|
* and read from
|
|
@@ -115,6 +132,22 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository {
|
|
this.cookieName = cookieName;
|
|
this.cookieName = cookieName;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Sets the HttpOnly attribute on the cookie containing the CSRF token.
|
|
|
|
+ * The cookie will only be marked as HttpOnly if both <code>cookieHttpOnly</code> is <code>true</code> and the underlying version of Servlet is 3.0 or greater.
|
|
|
|
+ * Defaults to <code>true</code> if the underlying version of Servlet is 3.0 or greater.
|
|
|
|
+ * NOTE: The {@link Cookie#setHttpOnly(boolean)} was introduced in Servlet 3.0.
|
|
|
|
+ *
|
|
|
|
+ * @param cookieHttpOnly <code>true</code> sets the HttpOnly attribute, <code>false</code> does not set it (depending on Servlet version)
|
|
|
|
+ * @throws IllegalArgumentException if <code>cookieHttpOnly</code> is <code>true</code> and the underlying version of Servlet is less than 3.0
|
|
|
|
+ */
|
|
|
|
+ public void setCookieHttpOnly(boolean cookieHttpOnly) {
|
|
|
|
+ if (cookieHttpOnly && setHttpOnlyMethod == null) {
|
|
|
|
+ throw new IllegalArgumentException("Cookie will not be marked as HttpOnly because you are using a version of Servlet less than 3.0. NOTE: The Cookie#setHttpOnly(boolean) was introduced in Servlet 3.0.");
|
|
|
|
+ }
|
|
|
|
+ this.cookieHttpOnly = cookieHttpOnly;
|
|
|
|
+ }
|
|
|
|
+
|
|
private String getCookiePath(HttpServletRequest request) {
|
|
private String getCookiePath(HttpServletRequest request) {
|
|
String contextPath = request.getContextPath();
|
|
String contextPath = request.getContextPath();
|
|
return contextPath.length() > 0 ? contextPath : "/";
|
|
return contextPath.length() > 0 ? contextPath : "/";
|