1 package com.atlassian.seraph.filter;
2
3 import com.atlassian.seraph.SecurityService;
4 import com.atlassian.seraph.auth.AuthType;
5 import com.atlassian.seraph.auth.AuthenticationContext;
6 import com.atlassian.seraph.auth.Authenticator;
7 import com.atlassian.seraph.auth.PrincipalNormaliser;
8 import com.atlassian.seraph.config.SecurityConfig;
9 import com.atlassian.seraph.config.SecurityConfigFactory;
10 import com.atlassian.seraph.util.RedirectUtils;
11 import org.apache.log4j.Category;
12
13 import javax.servlet.*;
14 import javax.servlet.http.Cookie;
15 import javax.servlet.http.HttpServletRequest;
16 import javax.servlet.http.HttpServletResponse;
17 import java.io.IOException;
18 import java.security.Principal;
19 import java.util.HashSet;
20 import java.util.Set;
21
22
23
24
25
26
27 public class SecurityFilter implements Filter
28 {
29 private FilterConfig config = null;
30 private SecurityConfig securityConfig = null;
31
32 private static final Category log = Category.getInstance(SecurityFilter.class);
33 static final String ALREADY_FILTERED = "os_securityfilter_already_filtered";
34 public static final String ORIGINAL_URL = "atlassian.core.seraph.original.url";
35
36 public void init(final FilterConfig config)
37 {
38 log.debug("SecurityFilter.init");
39 this.config = config;
40
41 String configFileLocation = null;
42
43 if (config.getInitParameter("config.file") != null)
44 {
45 configFileLocation = config.getInitParameter("config.file");
46 log.debug("Security config file location: " + configFileLocation);
47 }
48
49 securityConfig = SecurityConfigFactory.getInstance(configFileLocation);
50 config.getServletContext().setAttribute(SecurityConfig.STORAGE_KEY, securityConfig);
51 log.debug("SecurityFilter.init completed successfully.");
52 }
53
54 public void destroy()
55 {
56 log.debug("SecurityFilter.destroy");
57
58 if (securityConfig == null)
59 {
60 log.warn("Trying to destroy a SecurityFilter with null securityConfig.");
61 }
62 else
63 {
64
65 securityConfig.destroy();
66 securityConfig = null;
67 }
68 config = null;
69 }
70
71 public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException
72 {
73 if ((req.getAttribute(ALREADY_FILTERED) != null) || !getSecurityConfig().getController().isSecurityEnabled())
74 {
75 chain.doFilter(req, res);
76 return;
77 }
78 else
79 {
80 req.setAttribute(ALREADY_FILTERED, Boolean.TRUE);
81 }
82
83 final String METHOD = "doFilter : ";
84 final boolean dbg = log.isDebugEnabled();
85
86
87
88 if (req.getAttribute(BaseLoginFilter.ALREADY_FILTERED) == null)
89 {
90 log.warn(METHOD + "LoginFilter not yet applied to this request - terminating filter chain");
91 return;
92 }
93
94 final HttpServletRequest httpServletRequest = (HttpServletRequest) req;
95 final HttpServletResponse httpServletResponse = (HttpServletResponse) res;
96
97 final String originalURL = httpServletRequest.getServletPath() + (httpServletRequest.getPathInfo() == null ? "" : httpServletRequest.getPathInfo()) + (httpServletRequest.getQueryString() == null ? "" : "?" + httpServletRequest.getQueryString());
98
99
100 httpServletRequest.setAttribute(SecurityFilter.ORIGINAL_URL, originalURL);
101 if (dbg)
102 {
103 log.debug(METHOD + "Storing the originally requested URL (" + SecurityFilter.ORIGINAL_URL + "=" + originalURL + ")");
104 }
105
106 final Set<String> requiredRoles = new HashSet<String>();
107
108
109 for (final SecurityService service : getSecurityConfig().getServices())
110 {
111 final Set<String> serviceRoles = service.getRequiredRoles(httpServletRequest);
112 requiredRoles.addAll(serviceRoles);
113 }
114
115 if (dbg)
116 {
117 log.debug(METHOD + "requiredRoles = " + requiredRoles);
118 }
119
120
121 boolean needAuth = false;
122
123
124 final Authenticator authenticator = getSecurityConfig().getAuthenticator();
125 Principal user = authenticator.getUser(httpServletRequest, httpServletResponse);
126 if (authenticator instanceof PrincipalNormaliser)
127 {
128 user = ((PrincipalNormaliser) authenticator).normalisePrincipal(httpServletRequest,user);
129 }
130
131 if (user == null)
132 {
133 AuthType authType = AuthType.getAuthTypeInformation(httpServletRequest, getSecurityConfig());
134
135
136
137 if (RedirectUtils.isBasicAuthentication(httpServletRequest, getSecurityConfig().getAuthType()))
138 {
139
140 return;
141 }
142 else if (authType == AuthType.COOKIE && httpServletRequest.getSession(false) == null)
143 {
144 httpServletResponse.sendError(401, "os_authType was 'cookie' but no valid cookie was sent.");
145 return;
146 }
147 else if (authType == AuthType.ANY)
148 {
149
150
151 if (hasJSessionCookie(httpServletRequest.getCookies()) && httpServletRequest.getSession(false) == null)
152 {
153 httpServletResponse.sendError(401, "os_authType was 'any' and an invalid cookie was sent.");
154 return;
155 }
156 }
157 }
158
159
160 if (dbg)
161 {
162 log.debug(METHOD + "Setting Auth Context to be '" + (user == null ? "anonymous " : user.getName()) + "'");
163 }
164
165 final AuthenticationContext authenticationContext = getAuthenticationContext();
166 authenticationContext.setUser(user);
167
168
169
170 for (final Object element : requiredRoles)
171 {
172 final String role = (String) element;
173
174
175
176 if (!getSecurityConfig().getRoleMapper().hasRole(user, httpServletRequest, role))
177 {
178 log.info(METHOD + "'" + user + "' needs (and lacks) role '" + role + "' to access " + originalURL);
179 needAuth = true;
180 }
181 }
182
183
184 if ((httpServletRequest.getServletPath() != null) && httpServletRequest.getServletPath().equals(getSecurityConfig().getLoginURL()))
185 {
186 if (dbg)
187 {
188 log.debug(METHOD + "Login page requested so no additional authorization required.");
189 }
190 needAuth = false;
191 }
192
193
194 if (needAuth)
195 {
196 if (dbg)
197 {
198 log.debug(METHOD + "Need Authentication: Redirecting to: " + getSecurityConfig().getLoginURL() + " from: " + originalURL);
199 }
200
201 httpServletRequest.getSession().setAttribute(getSecurityConfig().getOriginalURLKey(), originalURL);
202
203 if (!httpServletResponse.isCommitted())
204 {
205 httpServletResponse.sendRedirect(RedirectUtils.getLoginUrl(httpServletRequest));
206 }
207
208
209 return;
210 }
211 else
212 {
213 try
214 {
215 chain.doFilter(req, res);
216 }
217 finally
218 {
219
220 authenticationContext.clearUser();
221 }
222 }
223 }
224
225 private boolean hasJSessionCookie(final Cookie[] cookies)
226 {
227 if (cookies == null)
228 {
229 return false;
230 }
231
232 for (Cookie cookie : cookies)
233 {
234 if (cookie.getName().equals("JSESSIONID"))
235 {
236 return true;
237 }
238 }
239
240 return false;
241 }
242
243 protected SecurityConfig getSecurityConfig()
244 {
245
246 if (securityConfig == null)
247 {
248 securityConfig = (SecurityConfig) config.getServletContext().getAttribute(SecurityConfig.STORAGE_KEY);
249 }
250 return securityConfig;
251 }
252
253 protected AuthenticationContext getAuthenticationContext()
254 {
255 return getSecurityConfig().getAuthenticationContext();
256 }
257
258 }