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