View Javadoc

1   package com.atlassian.plugins.rest.common.security.jersey;
2   
3   import com.atlassian.plugins.rest.common.security.XsrfCheckFailedException;
4   import com.atlassian.sal.api.web.context.HttpContext;
5   import com.atlassian.sal.api.xsrf.XsrfTokenAccessor;
6   import com.atlassian.sal.api.xsrf.XsrfTokenValidator;
7   import com.atlassian.sal.core.xsrf.IndependentXsrfTokenValidator;
8   import com.sun.jersey.spi.container.ContainerRequest;
9   import com.sun.jersey.spi.container.ContainerRequestFilter;
10  import com.sun.jersey.spi.container.ContainerResponseFilter;
11  import com.sun.jersey.spi.container.ResourceFilter;
12  
13  import javax.servlet.http.HttpServletRequest;
14  import javax.ws.rs.core.MediaType;
15  import java.util.Arrays;
16  import java.util.HashSet;
17  import java.util.Locale;
18  import java.util.Set;
19  
20  
21  /**
22   * A filter that filters requests that need XSRF protection.
23   * <p/>
24   * This checks for the presence of the no-check xsrf header and if the xsrf token is correct.
25   *
26   * @since 2.4
27   */
28  public class XsrfResourceFilter implements ResourceFilter, ContainerRequestFilter
29  {
30      public static final String TOKEN_HEADER = "X-Atlassian-Token";
31      public static final String NO_CHECK = "nocheck";
32  
33  
34      private HttpContext httpContext;
35      private XsrfTokenValidator xsrfTokenValidator;
36      private static final Set<String> XSRFABLE_TYPES = new HashSet<String>(Arrays.asList(
37              MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA, MediaType.TEXT_PLAIN
38      ));
39  
40  
41      public void setHttpContext(HttpContext httpContext)
42      {
43          this.httpContext = httpContext;
44      }
45  
46      public void setXsrfTokenValidator(final XsrfTokenValidator xsrfTokenValidator)
47      {
48          this.xsrfTokenValidator = xsrfTokenValidator;
49      }
50  
51      public ContainerRequest filter(final ContainerRequest request)
52      {
53          if (isXsrfable(request))
54          {
55              String header = request.getHeaderValue(TOKEN_HEADER);
56              if (header == null || !header.toLowerCase(Locale.ENGLISH).equals(NO_CHECK))
57              {
58                  HttpServletRequest httpServletRequest = null;
59                  if (httpContext != null)
60                  {
61                      httpServletRequest = this.httpContext.getRequest();
62                  }
63                  if (!isXsrfTokenValid(httpServletRequest))
64                  {
65                      throw new XsrfCheckFailedException();
66                  }
67              }
68          }
69          return request;
70      }
71  
72      private boolean isXsrfable(ContainerRequest request)
73      {
74          String method = request.getMethod();
75          return method.equals("GET") || (method.equals("POST") && XSRFABLE_TYPES.contains(mediaTypeToString(request.getMediaType())));
76      }
77  
78      public ContainerRequestFilter getRequestFilter()
79      {
80          return this;
81      }
82  
83      public ContainerResponseFilter getResponseFilter()
84      {
85          return null;
86      }
87  
88      private static String mediaTypeToString(MediaType mediaType)
89      {
90          return mediaType.getType().toLowerCase(Locale.ENGLISH) + "/" + mediaType.getSubtype().toLowerCase(Locale.ENGLISH);
91      }
92  
93      /**
94       * Returns true if the given request xsrf token cookie value
95       * matches the xsrf token submitted in the request form.
96       * Currently this method only works on requests that have a
97       * media type of {@link MediaType.APPLICATION_FORM_URLENCODED_TYPE}.
98       *
99       * @param request the request to check.
100      * @return true if the given request xsrf token cookie value
101      * matches the xsrf token submitted in the request form.
102      */
103     protected boolean isXsrfTokenValid(HttpServletRequest httpServletRequest)
104     {
105         if (httpServletRequest == null)
106         {
107             return false;
108         }
109         return xsrfTokenValidator.validateFormEncodedToken(httpServletRequest);
110     }
111 
112 }