1 package com.atlassian.seraph.filter;
2
3 import com.atlassian.seraph.RequestParameterConstants;
4 import com.atlassian.seraph.auth.AuthenticationContext;
5 import com.atlassian.seraph.auth.AuthenticationContextAwareAuthenticator;
6 import com.atlassian.seraph.auth.Authenticator;
7 import com.atlassian.seraph.config.SecurityConfig;
8 import com.atlassian.seraph.config.SecurityConfigFactory;
9 import com.atlassian.seraph.elevatedsecurity.ElevatedSecurityGuard;
10 import com.atlassian.seraph.util.RedirectUtils;
11 import org.apache.log4j.Logger;
12
13 import java.io.IOException;
14 import java.net.URI;
15 import java.net.URISyntaxException;
16 import java.security.Principal;
17 import javax.servlet.Filter;
18 import javax.servlet.FilterChain;
19 import javax.servlet.FilterConfig;
20 import javax.servlet.ServletException;
21 import javax.servlet.ServletRequest;
22 import javax.servlet.ServletResponse;
23 import javax.servlet.http.HttpServletRequest;
24 import javax.servlet.http.HttpServletRequestWrapper;
25 import javax.servlet.http.HttpServletResponse;
26 import javax.servlet.http.HttpSession;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 public abstract class BaseLoginFilter implements Filter
51 {
52 private static final Logger log = Logger.getLogger(BaseLoginFilter.class);
53
54 private FilterConfig filterConfig = null;
55 protected static final String ALREADY_FILTERED = "loginfilter.already.filtered";
56 public static final String LOGIN_SUCCESS = "success";
57 public static final String LOGIN_FAILED = "failed";
58 public static final String LOGIN_ERROR = "error";
59 public static final String LOGIN_NOATTEMPT = null;
60 public static final String OS_AUTHSTATUS_KEY = "os_authstatus";
61 public static final String AUTHENTICATION_ERROR_TYPE = "auth_error_type";
62 private SecurityConfig securityConfig = null;
63
64 public BaseLoginFilter()
65 {
66 super();
67 }
68
69 public void init(final FilterConfig config)
70 {
71 this.filterConfig = config;
72 }
73
74 public void destroy()
75 {
76 filterConfig = null;
77 }
78
79
80
81
82
83
84 public FilterConfig getFilterConfig()
85 {
86 return filterConfig;
87 }
88
89
90
91
92
93
94 public void setFilterConfig(final FilterConfig filterConfig)
95 {
96 if (filterConfig != null)
97 {
98 init(filterConfig);
99 }
100 }
101
102 public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain)
103 throws IOException, ServletException
104 {
105 final String METHOD = "doFilter : ";
106 final boolean dbg = log.isDebugEnabled();
107
108
109 HttpServletRequest httpServletRequest = new SecurityHttpRequestWrapper((HttpServletRequest) servletRequest);
110 HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
111
112 if (servletRequest.getAttribute(ALREADY_FILTERED) == null && getSecurityConfig().getController().isSecurityEnabled())
113 {
114 httpServletRequest.setAttribute(ALREADY_FILTERED, Boolean.TRUE);
115 httpServletRequest.setAttribute(OS_AUTHSTATUS_KEY, LOGIN_NOATTEMPT);
116
117 if (dbg)
118 {
119 log.debug(METHOD + "____ Attempting login for : '" + getRequestUrl(httpServletRequest) + "'");
120 }
121
122
123
124 String status = login(httpServletRequest, httpServletResponse);
125 httpServletRequest.setAttribute(OS_AUTHSTATUS_KEY, status);
126 if (dbg)
127 {
128 final String userName = httpServletRequest.getRemoteUser();
129 log.debug(METHOD + "Login completed for '" + userName + "' - " + OS_AUTHSTATUS_KEY + " = '" + status + "'");
130 }
131
132
133 if (LOGIN_SUCCESS.equals(status) && redirectToOriginalDestination(httpServletRequest, httpServletResponse))
134 {
135 return;
136 }
137
138
139 if (status == LOGIN_NOATTEMPT)
140 {
141 issuePossibleRedirectIfUserIsAlreadyLoggedIn(httpServletRequest, httpServletResponse);
142 }
143 }
144 filterChain.doFilter(httpServletRequest, httpServletResponse);
145 }
146
147 private String getRequestUrl(final HttpServletRequest httpServletRequest)
148 {
149 return httpServletRequest.getServletPath() +
150 (httpServletRequest.getPathInfo() == null ? "" : httpServletRequest.getPathInfo()) +
151 (httpServletRequest.getQueryString() == null ? "" : "?" + httpServletRequest.getQueryString());
152 }
153
154 private void issuePossibleRedirectIfUserIsAlreadyLoggedIn(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
155 throws IOException
156 {
157
158
159
160
161
162
163
164 if (httpServletRequest.getParameterMap().get(RequestParameterConstants.OS_DESTINATION) != null)
165 {
166 Principal principal = getAuthenticator().getUser(httpServletRequest, httpServletResponse);
167 if (principal != null)
168 {
169 HttpSession session = httpServletRequest.getSession();
170 if (session != null && session.getAttribute(SecurityConfigFactory.getInstance().getOriginalURLKey()) == null)
171 {
172 redirectToOriginalDestination(httpServletRequest, httpServletResponse);
173 }
174 }
175 }
176 }
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199 public abstract String login(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse);
200
201
202
203
204
205
206 class SecurityHttpRequestWrapper extends HttpServletRequestWrapper
207 {
208 private HttpServletRequest delegateHttpServletRequest;
209
210 public SecurityHttpRequestWrapper(final HttpServletRequest delegateHttpServletRequest)
211 {
212 super(delegateHttpServletRequest);
213 this.delegateHttpServletRequest = delegateHttpServletRequest;
214 }
215
216 public String getRemoteUser()
217 {
218 Principal user = getUserPrincipal();
219 return (user == null) ? null : user.getName();
220 }
221
222 public Principal getUserPrincipal()
223 {
224 if(getAuthenticator().getClass().isAnnotationPresent(AuthenticationContextAwareAuthenticator.class))
225 {
226 return getAuthenticationContext().getUser();
227 }
228 else
229 {
230 return getAuthenticator().getUser(delegateHttpServletRequest);
231 }
232 }
233 }
234
235
236
237
238
239
240
241
242
243
244
245 protected boolean redirectToOriginalDestination(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
246 throws IOException
247 {
248 final String METHOD = "redirectToOriginalDestination : ";
249 final boolean dbg = log.isDebugEnabled();
250
251
252 String redirectURL = (String) httpServletRequest.getSession().getAttribute(getSecurityConfig().getOriginalURLKey());
253 if (redirectURL != null)
254 {
255
256 httpServletRequest.getSession().setAttribute(getSecurityConfig().getOriginalURLKey(), null);
257 }
258 else
259 {
260
261 redirectURL = httpServletRequest.getParameter(RequestParameterConstants.OS_DESTINATION);
262 }
263
264 if (redirectURL == null)
265 {
266 return false;
267 }
268
269
270 if (!getSecurityConfig().getRedirectPolicy().allowedRedirectDestination(redirectURL, httpServletRequest))
271 {
272
273 log.warn(METHOD + "Redirect request to '" + redirectURL + "' is not allowed. Will send user to the context root instead.");
274
275 redirectURL = "/";
276 }
277
278 if (!isAbsoluteUrl(redirectURL))
279 {
280
281
282 redirectURL = RedirectUtils.appendPathToContext(httpServletRequest.getContextPath(), redirectURL);
283 }
284
285 if (dbg)
286 {
287 log.debug(METHOD + "Login redirect to: " + redirectURL);
288 }
289
290 httpServletResponse.sendRedirect(redirectURL);
291 return true;
292 }
293
294 protected boolean isAbsoluteUrl(final String url)
295 {
296 try
297 {
298 URI uri = new URI(url);
299 return uri.isAbsolute();
300 }
301 catch (URISyntaxException e)
302 {
303 return false;
304 }
305 }
306
307 protected Authenticator getAuthenticator()
308 {
309 return getSecurityConfig().getAuthenticator();
310 }
311
312 protected ElevatedSecurityGuard getElevatedSecurityGuard()
313 {
314 return getSecurityConfig().getElevatedSecurityGuard();
315 }
316
317 protected SecurityConfig getSecurityConfig()
318 {
319 if (securityConfig == null)
320 {
321 securityConfig = (SecurityConfig) filterConfig.getServletContext().getAttribute(SecurityConfig.STORAGE_KEY);
322 }
323 return securityConfig;
324 }
325
326 protected AuthenticationContext getAuthenticationContext()
327 {
328 return getSecurityConfig().getAuthenticationContext();
329 }
330 }