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
23
24
25
26
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
95
96
97
98
99
100
101
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 }