View Javadoc

1   package com.atlassian.seraph.filter;
2   
3   import com.atlassian.seraph.RequestParameterConstants;
4   import com.atlassian.seraph.auth.Authenticator;
5   import com.atlassian.seraph.config.SecurityConfig;
6   import com.atlassian.seraph.util.RedirectUtils;
7   import org.apache.log4j.Logger;
8   
9   import java.io.IOException;
10  import java.net.URI;
11  import java.net.URISyntaxException;
12  import java.security.Principal;
13  import javax.servlet.*;
14  import javax.servlet.http.HttpServletRequest;
15  import javax.servlet.http.HttpServletRequestWrapper;
16  import javax.servlet.http.HttpServletResponse;
17  
18  /**
19   * This is a base authentication filter. It delegates the actual login process to a child class but takes care of the redirection process.
20   * <p/>
21   * If the authentication is successful, the user will be redirected by the filter to the URL given
22   * by the session attribute at SecurityFilter.ORIGINAL_URL_KEY.
23   * <p/>
24   * If this URL doesn't exist, it will look for a parameter 'os_destination' to use as the redirected URL instead.
25   * <p/>
26   * If neither is found, it is assumed that the page will check the authorisation status and handle redirection itself.
27   * <p/>
28   * From the any other filter in the request, or the servlet/JSP/action which processes the request, you can look up the
29   * status of the authorisation attempt. The status is a String request attribute, with the key 'os_authstatus'.
30   * <p/>
31   * The possible statuses are:
32   * <ul>
33   * <li> LoginFilter.LOGIN_SUCCESS - the login was processed, and user was logged in
34   * <li> LoginFilter.LOGIN_FAILURE - the login was processed, the user gave a bad username or password
35   * <li> LoginFilter.LOGIN_ERROR - the login was processed, an exception occurred trying to log the user in
36   * <li> LoginFilter.LOGIN_NOATTEMPT - the login was no processed, no form parameters existed
37   * </ul>
38   */
39  public abstract class BaseLoginFilter implements Filter
40  {
41      private static final Logger log = Logger.getLogger(BaseLoginFilter.class);
42  
43      private FilterConfig filterConfig = null;
44      protected static final String ALREADY_FILTERED = "loginfilter.already.filtered";
45      public static final String LOGIN_SUCCESS = "success";
46      public static final String LOGIN_FAILED = "failed";
47      public static final String LOGIN_ERROR = "error";
48      public static final String LOGIN_NOATTEMPT = null;
49      public static final String OS_AUTHSTATUS_KEY = "os_authstatus";
50      private SecurityConfig securityConfig = null;
51  
52      public BaseLoginFilter()
53      {
54          super();
55      }
56  
57      public void init(FilterConfig config)
58      {
59          // log.debug("LoginFilter.init");
60          this.filterConfig = config;
61      }
62  
63      public void destroy()
64      {
65          // log.debug("LoginFilter.destroy");
66          filterConfig = null;
67      }
68  
69      /**
70       * @deprecated Not needed in latest version of Servlet 2.3 API
71       */
72      public FilterConfig getFilterConfig()
73      {
74          return filterConfig;
75      }
76  
77      /**
78       * @deprecated Not needed in latest version of Servlet 2.3 API - replaced by init().
79       */
80      public void setFilterConfig(FilterConfig filterConfig)
81      {
82          if (filterConfig != null) //it seems that Orion 1.5.2 calls this with a null config.
83          {
84              init(filterConfig);
85          }
86      }
87  
88      public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
89              throws IOException, ServletException
90      {
91          final boolean dbg = log.isDebugEnabled();
92          // wrap the request with one that returns the User as the Principal
93          req = new SecurityHttpRequestWrapper((HttpServletRequest) req);
94  
95          if (req.getAttribute(ALREADY_FILTERED) == null && getSecurityConfig().getController().isSecurityEnabled())
96          {
97              req.setAttribute(ALREADY_FILTERED, Boolean.TRUE);
98              req.setAttribute(OS_AUTHSTATUS_KEY, LOGIN_NOATTEMPT);
99  
100             HttpServletRequest request = (HttpServletRequest) req;
101             HttpServletResponse response = (HttpServletResponse) res;
102 
103             if (dbg)
104             {
105                 String url = request.getServletPath() +
106                              (request.getPathInfo() == null ? "" : request.getPathInfo()) +
107                              (request.getQueryString() == null ? "" : "?" + request.getQueryString());
108                 log.debug("____ Attempting login for : '" + url + "'");
109             }
110 
111             String status = login(request, response);
112             request.setAttribute(OS_AUTHSTATUS_KEY, status);
113             if (dbg)
114             {
115                 log.debug("Login completed - set " + OS_AUTHSTATUS_KEY + " attribute to '" + status + "'");
116             }
117 
118             // if we successfully logged in - look for an original URL to forward to
119             if (status == LOGIN_SUCCESS && redirectToOriginalDestination(request, response))
120             {
121                 return;
122             }
123         }
124 
125         chain.doFilter(req, res);
126     }
127 
128     /**
129      * Performs the actual authentication (if required) and returns the status code. Status code is chosen to be one of these:
130      * <p/>
131      * The possible statuses are:
132      * <ul>
133      * <li> BaseLoginFilter.LOGIN_SUCCESS - the login was processed, and user was logged in
134      * <li> BaseLoginFilter.LOGIN_FAILURE - the login was processed, the user gave a bad username or password
135      * <li> BaseLoginFilter.LOGIN_ERROR - the login was processed, an exception occurred trying to log the user in
136      * <li> BaseLoginFilter.LOGIN_NOATTEMPT - the login was no processed, no form parameters existed
137      * </ul>
138      *
139      * @param request
140      * @param response
141      * @return authentication status
142      */
143     public abstract String login(HttpServletRequest request, HttpServletResponse response);
144 
145     private class SecurityHttpRequestWrapper extends HttpServletRequestWrapper
146     {
147         private HttpServletRequest request;
148 
149         public SecurityHttpRequestWrapper(HttpServletRequest request)
150         {
151             super(request);
152             this.request = request;
153         }
154 
155         public String getRemoteUser()
156         {
157             Principal user = getUserPrincipal();
158             return (user == null) ? null : user.getName();
159         }
160 
161         public Principal getUserPrincipal()
162         {
163             return getSecurityConfig().getAuthenticator().getUser(request);
164         }
165     }
166 
167     /**
168      * Redirect the response to the original destination if present
169      *
170      * @param request
171      * @param response
172      * @return true if a redirect was needed and issued
173      * @throws IOException
174      */
175     protected boolean redirectToOriginalDestination(HttpServletRequest request, HttpServletResponse response)
176             throws IOException
177     {
178         String originalURL = (String) request.getSession().getAttribute(getSecurityConfig().getOriginalURLKey());
179         String destinationURL = request.getParameter(RequestParameterConstants.OS_DESTINATION);
180         String redirectURL = null;
181 
182         if (originalURL != null)
183         {
184             request.getSession().setAttribute(getSecurityConfig().getOriginalURLKey(), null);
185             redirectURL = originalURL;
186         }
187         else if (destinationURL != null)
188         {
189             redirectURL = destinationURL;
190         }
191 
192         if (redirectURL == null)
193         {
194             return false;
195         }
196 
197         if (!isAbsoluteUrl(redirectURL))
198         {
199             redirectURL = RedirectUtils.appendPathToContext(request.getContextPath(), redirectURL);
200         }
201 
202         if (log.isDebugEnabled())
203         {
204             log.debug("Logged In - redirecting to: " + redirectURL);
205         }
206 
207         response.sendRedirect(redirectURL);
208         return true;
209     }
210 
211     protected boolean isAbsoluteUrl(String url)
212     {
213         try
214         {
215             URI uri = new URI(url);
216             return uri.isAbsolute();
217         }
218         catch (URISyntaxException e)
219         {
220             return false;
221         }
222     }
223 
224     protected Authenticator getAuthenticator()
225     {
226         return getSecurityConfig().getAuthenticator();
227     }
228 
229     protected SecurityConfig getSecurityConfig()
230     {
231         if (securityConfig == null)
232         {
233             securityConfig = (SecurityConfig) filterConfig.getServletContext().getAttribute(SecurityConfig.STORAGE_KEY);
234         }
235         return securityConfig;
236     }
237 }