1   package com.atlassian.seraph.config;
2   
3   import com.atlassian.seraph.util.RedirectUtils;
4   
5   import java.net.URI;
6   import java.net.URISyntaxException;
7   import java.util.Map;
8   
9   import javax.servlet.http.HttpServletRequest;
10  
11  public class DefaultRedirectPolicy implements RedirectPolicy
12  {
13      private boolean allowAnyUrl = false;
14  
15      public void init(final Map<String, String> params, final SecurityConfig config)
16      {
17          // params is never allowed to be null.
18          if (params == null)
19          {
20              throw new IllegalArgumentException("params is not allowed to be null");
21          }
22          // Allow applications to set allow.any.redirect.url=true for legacy behaviour
23          allowAnyUrl = "true".equals(params.get("allow.any.redirect.url"));
24      }
25  
26      /**
27       * Returns true if we allow redirect to any URL at all.
28       * By default this is false, however it may be configured to true in the Seraph config file to allow legacy behaviour.
29       *
30       * @return true if we allow redirect to any URL at all.
31       */
32      public boolean isAllowAnyUrl()
33      {
34          return allowAnyUrl;
35      }
36  
37      /**
38       * Checks if the given redirectURL is permitted.
39       * <p/>
40       * Uses the configured redirect rules to see if we are allowed to redirect to the given URL.
41       * By default, the following is allowed:
42       * <ul>
43       *   <li>Any relative URL</li>
44       *   <li>An absolute URL to the same context path as the current incoming request</li>
45       * </ul>
46       * You can configure this "security-policy" in the Seraph XML config file.
47       * eg:
48       * <pre>
49       *  &lt;redirect-policy class="com.atlassian.seraph.config.SimpleRedirectPolicy"&gt;
50       *    &lt;init-param&gt;
51       *      &lt;param-name&gt;allow.any.redirect.url&lt;/param-name&gt;
52       *      &lt;param-value&gt;true&lt;/param-value&gt;
53       *    &lt;/init-param&gt;
54       *  &lt;/redirect-policy&gt;
55       * </pre>
56       * <p/>
57       *
58       * @param redirectUrl Requested redirect URL to be verified.
59       * @param request The current incoming request.
60       * @return <code>true</code> if this redirectURL is allowed.
61       */
62      public boolean allowedRedirectDestination(final String redirectUrl, final HttpServletRequest request)
63      {
64          // Test for total trust
65          if (allowAnyUrl)
66          {
67              return true;
68          }
69          // Otherwise we use default behaviour: allow valid redirects to the same context.
70          URI uri;
71          try
72          {
73              // Attempt to parse the URI
74              uri = new URI(redirectUrl);
75          }
76          catch (final URISyntaxException e)
77          {
78              // Invalid URI - not allowed. This stops possible header injection attacks (see SER-127)
79              // but it is also good in general that if we can't parse a URI, then we can't trust it.
80              return false;
81          }
82          // The URI is valid - if it is absolute, then check that it is to the same context
83          return !uri.isAbsolute() || RedirectUtils.sameContext(redirectUrl, request);
84      }
85  }