1 package com.atlassian.xwork.interceptors;
2
3 import com.opensymphony.xwork.interceptor.Interceptor;
4 import com.opensymphony.xwork.ActionInvocation;
5 import com.opensymphony.webwork.ServletActionContext;
6 import com.atlassian.xwork.PermittedMethods;
7 import com.atlassian.xwork.HttpMethod;
8
9 import javax.servlet.http.HttpServletRequest;
10 import java.lang.reflect.Method;
11 import java.util.List;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14
15 import org.apache.log4j.Logger;
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public abstract class RestrictHttpMethodInterceptor implements Interceptor
44 {
45 private static final Logger log = Logger.getLogger(RestrictHttpMethodInterceptor.class);
46 public static final String INVALID_METHOD_RESULT = "invalidmethod";
47 public static final String PERMITTED_METHODS_PARAM_NAME = "permittedMethods";
48
49 public static enum SecurityLevel {
50
51 NONE
52 {
53 @Override
54 public boolean isPermitted(String invocationMethodName, HttpMethod[] permittedMethods, String httpMethod)
55 {
56 return true;
57 }
58 },
59
60 OPT_IN
61 {
62 @Override
63 public boolean isPermitted(String invocationMethodName, HttpMethod[] permittedMethods, String httpMethod)
64 {
65 if (permittedMethods.length == 0)
66 return true;
67
68 return methodMatches(httpMethod, permittedMethods);
69 }
70 },
71
72
73
74
75 DEFAULT
76 {
77 @Override
78 public boolean isPermitted(String invocationMethodName, HttpMethod[] permittedMethods, String httpMethod)
79 {
80 if (permittedMethods.length == 0)
81 {
82 if (invocationMethodName.equals("doDefault"))
83 return methodMatches(httpMethod, HttpMethod.GET, HttpMethod.POST);
84 else
85 return methodMatches(httpMethod, HttpMethod.POST);
86 }
87
88 return methodMatches(httpMethod, permittedMethods);
89 }
90 },
91
92
93
94 STRICT
95 {
96 @Override
97 public boolean isPermitted(String invocationMethodName, HttpMethod[] permittedMethods, String httpMethod)
98 {
99 return methodMatches(httpMethod, permittedMethods);
100 }
101 };
102
103 private static boolean methodMatches(String httpMethod, HttpMethod... allowedMethods)
104 {
105 for (HttpMethod allowedMethod : allowedMethods)
106 {
107 if (allowedMethod.matches(httpMethod))
108 return true;
109 }
110
111 return false;
112 }
113
114 public abstract boolean isPermitted(String invocationMethodName, HttpMethod[] permittedMethods, String httpMethod);
115 }
116
117 public final String intercept(ActionInvocation invocation) throws Exception
118 {
119 Method invocationMethod = invocation.getProxy().getConfig().getMethod();
120 String configParam = (String) invocation.getProxy().getConfig().getParams().get(PERMITTED_METHODS_PARAM_NAME);
121 PermittedMethods annotation = invocationMethod.getAnnotation(PermittedMethods.class);
122 HttpMethod[] permittedMethods = toPermittedMethodArray(configParam, annotation);
123
124 String httpMethod = getHttpMethod();
125
126 if (log.isDebugEnabled())
127 log.debug("Checking HTTP method: " + getHttpMethod() + " permitted against " + fullMethodName(invocationMethod));
128
129 if (getSecurityLevel().isPermitted(invocationMethod.getName(), permittedMethods, httpMethod))
130 {
131 log.debug("Invocation proceeding");
132 return invocation.invoke();
133 }
134 else
135 {
136
137 log.info("Refusing HTTP method: " + httpMethod + " against " + fullMethodName(invocationMethod) + " (configured allowed methods: " + Arrays.toString(permittedMethods) + ")");
138 return INVALID_METHOD_RESULT;
139 }
140 }
141
142 private HttpMethod[] toPermittedMethodArray(String configParam, PermittedMethods annotation)
143 {
144 if (configParam != null && configParam.trim().length() > 0)
145 {
146 String[] methodNames = configParam.trim().split("\\s*,\\s*");
147 List<HttpMethod> permittedMethods = new ArrayList<HttpMethod>(methodNames.length);
148 for (String methodName : methodNames)
149 {
150 try
151 {
152 permittedMethods.add(HttpMethod.valueOf(methodName));
153 }
154 catch (IllegalArgumentException e)
155 {
156 log.error("XWork configuration error: " + methodName + " is not a recognised HTTP method (method names are case sensitive).");
157 }
158 }
159
160 return permittedMethods.toArray(new HttpMethod[permittedMethods.size()]);
161 }
162 else if (annotation != null)
163 {
164 return annotation.value();
165 }
166 else
167 {
168 return new HttpMethod[0];
169 }
170 }
171
172 private String fullMethodName(Method invocationMethod)
173 {
174 return invocationMethod.getDeclaringClass().getName() + "#" + invocationMethod.getName();
175 }
176
177 private String getHttpMethod()
178 {
179 HttpServletRequest servletRequest = ServletActionContext.getRequest();
180 return servletRequest == null ? "" : servletRequest.getMethod();
181 }
182
183
184 public final void destroy()
185 {
186 }
187
188 public final void init()
189 {
190 }
191
192
193
194
195
196
197
198
199 protected SecurityLevel getSecurityLevel()
200 {
201 return SecurityLevel.DEFAULT;
202 }
203 }