1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.captcha;
17
18 import org.acegisecurity.securechannel.ChannelEntryPoint;
19 import org.acegisecurity.util.PortMapper;
20 import org.acegisecurity.util.PortMapperImpl;
21 import org.acegisecurity.util.PortResolver;
22 import org.acegisecurity.util.PortResolverImpl;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 import org.springframework.beans.factory.InitializingBean;
28
29 import org.springframework.util.Assert;
30
31 import java.io.IOException;
32 import java.io.UnsupportedEncodingException;
33
34 import java.net.URLEncoder;
35
36 import java.util.Enumeration;
37
38 import javax.servlet.ServletException;
39 import javax.servlet.ServletRequest;
40 import javax.servlet.ServletResponse;
41 import javax.servlet.http.HttpServletRequest;
42 import javax.servlet.http.HttpServletResponse;
43
44
45 /***
46 * The captcha entry point : redirect to the captcha test page. <br>
47 *
48 * <p>
49 * This entry point can force the use of SSL : see {@link #getForceHttps()}<br>
50 * </p>
51 * This entry point allows internal OR external redirect : see {@link #setOutsideWebApp(boolean)}<br>
52 * / Original request can be added to the redirect path using a custom
53 * translation : see {@link #setIncludeOriginalRequest(boolean)}<br>
54 * Original request is translated using URLEncoding and the following
55 * translation mapping in the redirect url :
56 *
57 * <ul>
58 * <li>
59 * original url => {@link #getOriginalRequestUrlParameterName()}
60 * </li>
61 * <li>
62 * If {@link #isIncludeOriginalParameters()}
63 * </li>
64 * <li>
65 * original method => {@link #getOriginalRequestMethodParameterName()}
66 * </li>
67 * <li>
68 * original parameters => {@link #getOriginalRequestParametersParameterName()}
69 * </li>
70 * <li>
71 * The original parameters string is contructed using :
72 *
73 * <ul>
74 * <li>
75 * a parameter separator {@link #getOriginalRequestParametersSeparator()}
76 * </li>
77 * <li>
78 * a parameter name value pair separator for each parameter {@link
79 * #getOriginalRequestParametersNameValueSeparator()}
80 * </li>
81 * </ul>
82 *
83 * </li>
84 * </ul>
85 *
86 * <br><br>
87 * Default values :<br>
88 * forceHttps = false<br>
89 * includesOriginalRequest = true<br>
90 * includesOriginalParameters = false<br>
91 * isOutsideWebApp=false<br>
92 * originalRequestUrlParameterName =original_requestUrl <br>
93 * originalRequestParametersParameterName = original_request_parameters<br>
94 * originalRequestParametersNameValueSeparator = __ <br>
95 * originalRequestParametersSeparator = ;; <br>
96 * originalRequestMethodParameterName = original_request_method <br>
97 * urlEncodingCharset = UTF-8<br>
98 *
99 * @author marc antoine Garrigue
100 * @version $Id: CaptchaEntryPoint.java,v 1.4 2005/11/17 00:55:49 benalex Exp $
101 */
102 public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean {
103
104
105
106
107 private static final Log logger = LogFactory.getLog(CaptchaEntryPoint.class);
108
109
110
111
112
113 private PortMapper portMapper = new PortMapperImpl();
114 private PortResolver portResolver = new PortResolverImpl();
115 private String captchaFormUrl;
116 private String originalRequestMethodParameterName = "original_request_method";
117 private String originalRequestParametersNameValueSeparator = "__";
118 private String originalRequestParametersParameterName = "original_request_parameters";
119 private String originalRequestParametersSeparator = ";;";
120 private String originalRequestUrlParameterName = "original_requestUrl";
121 private String urlEncodingCharset = "UTF-8";
122 private boolean forceHttps = false;
123 private boolean includeOriginalParameters = false;
124 private boolean includeOriginalRequest = true;
125 private boolean isOutsideWebApp = false;
126
127
128
129 /***
130 * The URL where the <code>CaptchaProcessingFilter</code> login page can be
131 * found. Should be relative to the web-app context path, and include a
132 * leading <code>/</code>
133 *
134 * @param captchaFormUrl
135 */
136 public void setCaptchaFormUrl(String captchaFormUrl) {
137 this.captchaFormUrl = captchaFormUrl;
138 }
139
140 /***
141 * DOCUMENT ME!
142 *
143 * @return the captcha test page to redirect to.
144 */
145 public String getCaptchaFormUrl() {
146 return captchaFormUrl;
147 }
148
149
150
151
152 /***
153 * Set to true to force captcha form access to be via https. If this value
154 * is ture (the default is false), and the incoming request for the
155 * protected resource which triggered the interceptor was not already
156 * <code>https</code>, then
157 *
158 * @param forceHttps
159 */
160 public void setForceHttps(boolean forceHttps) {
161 this.forceHttps = forceHttps;
162 }
163
164 public boolean getForceHttps() {
165 return forceHttps;
166 }
167
168 public void setIncludeOriginalParameters(boolean includeOriginalParameters) {
169 this.includeOriginalParameters = includeOriginalParameters;
170 }
171
172 public boolean isIncludeOriginalParameters() {
173 return includeOriginalParameters;
174 }
175
176 /***
177 * If set to true, the original request url will be appended to the
178 * redirect url using the {@link #getOriginalRequestUrlParameterName()}.
179 *
180 * @param includeOriginalRequest
181 */
182 public void setIncludeOriginalRequest(boolean includeOriginalRequest) {
183 this.includeOriginalRequest = includeOriginalRequest;
184 }
185
186 public boolean isIncludeOriginalRequest() {
187 return includeOriginalRequest;
188 }
189
190 public void setOriginalRequestMethodParameterName(
191 String originalRequestMethodParameterName) {
192 this.originalRequestMethodParameterName = originalRequestMethodParameterName;
193 }
194
195 public String getOriginalRequestMethodParameterName() {
196 return originalRequestMethodParameterName;
197 }
198
199 public void setOriginalRequestParametersNameValueSeparator(
200 String originalRequestParametersNameValueSeparator) {
201 this.originalRequestParametersNameValueSeparator = originalRequestParametersNameValueSeparator;
202 }
203
204 public String getOriginalRequestParametersNameValueSeparator() {
205 return originalRequestParametersNameValueSeparator;
206 }
207
208 public void setOriginalRequestParametersParameterName(
209 String originalRequestParametersParameterName) {
210 this.originalRequestParametersParameterName = originalRequestParametersParameterName;
211 }
212
213 public String getOriginalRequestParametersParameterName() {
214 return originalRequestParametersParameterName;
215 }
216
217 public void setOriginalRequestParametersSeparator(
218 String originalRequestParametersSeparator) {
219 this.originalRequestParametersSeparator = originalRequestParametersSeparator;
220 }
221
222 public String getOriginalRequestParametersSeparator() {
223 return originalRequestParametersSeparator;
224 }
225
226 public void setOriginalRequestUrlParameterName(
227 String originalRequestUrlParameterName) {
228 this.originalRequestUrlParameterName = originalRequestUrlParameterName;
229 }
230
231 public String getOriginalRequestUrlParameterName() {
232 return originalRequestUrlParameterName;
233 }
234
235 /***
236 * if set to true, the {@link #commence(ServletRequest, ServletResponse)}
237 * method uses the {@link #getCaptchaFormUrl()} as a complete URL, else it
238 * as a 'inside WebApp' path.
239 *
240 * @param isOutsideWebApp
241 */
242 public void setOutsideWebApp(boolean isOutsideWebApp) {
243 this.isOutsideWebApp = isOutsideWebApp;
244 }
245
246 public boolean isOutsideWebApp() {
247 return isOutsideWebApp;
248 }
249
250 public void setPortMapper(PortMapper portMapper) {
251 this.portMapper = portMapper;
252 }
253
254 public PortMapper getPortMapper() {
255 return portMapper;
256 }
257
258 public void setPortResolver(PortResolver portResolver) {
259 this.portResolver = portResolver;
260 }
261
262 public PortResolver getPortResolver() {
263 return portResolver;
264 }
265
266 public void setUrlEncodingCharset(String urlEncodingCharset) {
267 this.urlEncodingCharset = urlEncodingCharset;
268 }
269
270 public String getUrlEncodingCharset() {
271 return urlEncodingCharset;
272 }
273
274 public void afterPropertiesSet() throws Exception {
275 Assert.hasLength(captchaFormUrl, "captchaFormUrl must be specified");
276 Assert.hasLength(originalRequestMethodParameterName,
277 "originalRequestMethodParameterName must be specified");
278 Assert.hasLength(originalRequestParametersNameValueSeparator,
279 "originalRequestParametersNameValueSeparator must be specified");
280 Assert.hasLength(originalRequestParametersParameterName,
281 "originalRequestParametersParameterName must be specified");
282 Assert.hasLength(originalRequestParametersSeparator,
283 "originalRequestParametersSeparator must be specified");
284 Assert.hasLength(originalRequestUrlParameterName,
285 "originalRequestUrlParameterName must be specified");
286 Assert.hasLength(urlEncodingCharset,
287 "urlEncodingCharset must be specified");
288 Assert.notNull(portMapper, "portMapper must be specified");
289 Assert.notNull(portResolver, "portResolver must be specified");
290 URLEncoder.encode(" fzaef é& à ", urlEncodingCharset);
291 }
292
293 public void commence(ServletRequest request, ServletResponse response)
294 throws IOException, ServletException {
295 StringBuffer redirectUrl = new StringBuffer();
296 HttpServletRequest req = (HttpServletRequest) request;
297
298 if (isOutsideWebApp) {
299 redirectUrl = redirectUrl.append(captchaFormUrl);
300 } else {
301 buildInternalRedirect(redirectUrl, req);
302 }
303
304 if (includeOriginalRequest) {
305 includeOriginalRequest(redirectUrl, req);
306 }
307
308
309 if (logger.isDebugEnabled()) {
310 logger.debug("Redirecting to: " + redirectUrl);
311 }
312
313 ((HttpServletResponse) response).sendRedirect(redirectUrl.toString());
314 }
315
316 private void buildInternalRedirect(StringBuffer redirectUrl,
317 HttpServletRequest req) {
318
319 StringBuffer simpleRedirect = new StringBuffer();
320
321 String scheme = req.getScheme();
322 String serverName = req.getServerName();
323 int serverPort = portResolver.getServerPort(req);
324 String contextPath = req.getContextPath();
325 boolean includePort = true;
326
327 if ("http".equals(scheme.toLowerCase()) && (serverPort == 80)) {
328 includePort = false;
329 }
330
331 if ("https".equals(scheme.toLowerCase()) && (serverPort == 443)) {
332 includePort = false;
333 }
334
335 simpleRedirect.append(scheme);
336 simpleRedirect.append("://");
337 simpleRedirect.append(serverName);
338
339 if (includePort) {
340 simpleRedirect.append(":");
341 simpleRedirect.append(serverPort);
342 }
343
344 simpleRedirect.append(contextPath);
345 simpleRedirect.append(captchaFormUrl);
346
347 if (forceHttps && req.getScheme().equals("http")) {
348 Integer httpPort = new Integer(portResolver.getServerPort(req));
349 Integer httpsPort = (Integer) portMapper.lookupHttpsPort(httpPort);
350
351 if (httpsPort != null) {
352 if (httpsPort.intValue() == 443) {
353 includePort = false;
354 } else {
355 includePort = true;
356 }
357
358 redirectUrl.append("https://");
359 redirectUrl.append(serverName);
360
361 if (includePort) {
362 redirectUrl.append(":");
363 redirectUrl.append(httpsPort);
364 }
365
366 redirectUrl.append(contextPath);
367 redirectUrl.append(captchaFormUrl);
368 } else {
369 redirectUrl.append(simpleRedirect);
370 }
371 } else {
372 redirectUrl.append(simpleRedirect);
373 }
374 }
375
376 private void includeOriginalRequest(StringBuffer redirectUrl,
377 HttpServletRequest req) {
378
379 if (redirectUrl.indexOf("?") >= 0) {
380 redirectUrl.append("&");
381 } else {
382 redirectUrl.append("?");
383 }
384
385 redirectUrl.append(originalRequestUrlParameterName);
386 redirectUrl.append("=");
387
388 try {
389 redirectUrl.append(URLEncoder.encode(req.getRequestURL().toString(),
390 urlEncodingCharset));
391 } catch (UnsupportedEncodingException e) {
392 logger.warn(e);
393 }
394
395
396 redirectUrl.append("&");
397 redirectUrl.append(originalRequestMethodParameterName);
398 redirectUrl.append("=");
399 redirectUrl.append(req.getMethod());
400
401 if (includeOriginalParameters) {
402
403 redirectUrl.append("&");
404 redirectUrl.append(originalRequestParametersParameterName);
405 redirectUrl.append("=");
406
407 StringBuffer qp = new StringBuffer();
408 Enumeration parameters = req.getParameterNames();
409
410 if ((parameters != null) && parameters.hasMoreElements()) {
411
412 while (parameters.hasMoreElements()) {
413 String name = parameters.nextElement().toString();
414 String value = req.getParameter(name);
415 qp.append(name);
416 qp.append(originalRequestParametersNameValueSeparator);
417 qp.append(value);
418
419 if (parameters.hasMoreElements()) {
420 qp.append(originalRequestParametersSeparator);
421 }
422 }
423 }
424
425 try {
426 redirectUrl.append(URLEncoder.encode(qp.toString(),
427 urlEncodingCharset));
428 } catch (Exception e) {
429 logger.warn(e);
430 }
431 }
432 }
433 }