Class DSpaceCsrfTokenRepository

java.lang.Object
org.dspace.app.rest.security.DSpaceCsrfTokenRepository
All Implemented Interfaces:
org.springframework.security.web.csrf.CsrfTokenRepository

public class DSpaceCsrfTokenRepository extends Object implements org.springframework.security.web.csrf.CsrfTokenRepository
This is a custom Spring Security CsrfTokenRepository which supports *cross-domain* CSRF protection (allowing the client and backend to be on different domains). It's inspired by https://stackoverflow.com/a/33175322

This also borrows heavily from Spring Security's CookieCsrfTokenRepository: https://github.com/spring-projects/spring-security/blob/5.2.x/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java How it works: 1. Backend generates XSRF token & stores in a *server-side* cookie named DSPACE-XSRF-COOKIE. By default, this cookie is not readable to JS clients (HttpOnly=true). But, it is returned (by user's browser) on every subsequent request to backend. See "saveToken()" method below. 2. At the same time, backend also sends the generated XSRF token in a header named DSPACE-XSRF-TOKEN to client. See "saveToken()" method below. 3. Client MUST look for DSPACE-XSRF-TOKEN header in a response from backend. If found, the client MUST store/save this token for later request(s). For Angular UI, this task is performed by the XsrfInterceptor. 4. Whenever the client is making a mutating request (e.g. POST, PUT, DELETE, etc), the XSRF token is REQUIRED to be sent back in the X-XSRF-TOKEN header. * NOTE: non-mutating requests (e.g. GET, HEAD) do not check for an XSRF token. This is default behavior in Spring Security 5. On backend, the X-XSRF-TOKEN header is received & compared to the current value of the *server-side* cookie named DSPACE-XSRF-COOKIE. If tokens match, the request is accepted. If tokens don't match a 403 is returned. This is done automatically by Spring Security. In summary, the XSRF token is ALWAYS sent to/from the client & backend via *headers*. This is what allows the client and backend to be on different domains. The server-side cookie named DSPACE-XSRF-COOKIE is (usually) not accessible to the client. It only exists to allow the server-side to remember the currently active XSRF token, so that it can validate the token sent (by the client) in the X-XSRF-TOKEN header.

  • Field Details

  • Constructor Details

    • DSpaceCsrfTokenRepository

      public DSpaceCsrfTokenRepository()
  • Method Details

    • generateToken

      public org.springframework.security.web.csrf.CsrfToken generateToken(javax.servlet.http.HttpServletRequest request)
      Specified by:
      generateToken in interface org.springframework.security.web.csrf.CsrfTokenRepository
    • saveToken

      public void saveToken(org.springframework.security.web.csrf.CsrfToken token, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
      This method has been modified for DSpace.

      It now uses ResponseCookie to build the cookie, so that the "SameSite" attribute can be applied.

      It also sends the token (if not empty) in both the cookie and the custom "DSPACE-XSRF-TOKEN" header

      Specified by:
      saveToken in interface org.springframework.security.web.csrf.CsrfTokenRepository
      Parameters:
      token - current token
      request - current request
      response - current response
    • loadToken

      public org.springframework.security.web.csrf.CsrfToken loadToken(javax.servlet.http.HttpServletRequest request)
      Specified by:
      loadToken in interface org.springframework.security.web.csrf.CsrfTokenRepository
    • setParameterName

      public void setParameterName(String parameterName)
      Sets the name of the HTTP request parameter that should be used to provide a token.
      Parameters:
      parameterName - the name of the HTTP request parameter that should be used to provide a token
    • setHeaderName

      public void setHeaderName(String headerName)
      Sets the name of the HTTP header that should be used to provide the token.
      Parameters:
      headerName - the name of the HTTP header that should be used to provide the token
    • setCookieName

      public void setCookieName(String cookieName)
      Sets the name of the cookie that the expected CSRF token is saved to and read from.
      Parameters:
      cookieName - the name of the cookie that the expected CSRF token is saved to and read from
    • setCookieHttpOnly

      public void setCookieHttpOnly(boolean cookieHttpOnly)
      Sets the HttpOnly attribute on the cookie containing the CSRF token. Defaults to true.
      Parameters:
      cookieHttpOnly - true sets the HttpOnly attribute, false does not set it
    • withHttpOnlyFalse

      public static DSpaceCsrfTokenRepository withHttpOnlyFalse()
      Factory method to conveniently create an instance that has setCookieHttpOnly(boolean) set to false.
      Returns:
      an instance of CookieCsrfTokenRepository with setCookieHttpOnly(boolean) set to false
    • setCookiePath

      public void setCookiePath(String path)
      Set the path that the Cookie will be created with. This will override the default functionality which uses the request context as the path.
      Parameters:
      path - the path to use
    • getCookiePath

      public String getCookiePath()
      Get the path that the CSRF cookie will be set to.
      Returns:
      the path to be used.
    • setCookieDomain

      public void setCookieDomain(String cookieDomain)
      Sets the domain of the cookie that the expected CSRF token is saved to and read from.
      Parameters:
      cookieDomain - the domain of the cookie that the expected CSRF token is saved to and read from
      Since:
      5.2