1 package com.atlassian.seraph.config;
2
3 import com.atlassian.seraph.auth.RoleMapper;
4 import com.atlassian.seraph.auth.Authenticator;
5 import com.atlassian.seraph.auth.AuthenticationContext;
6 import com.atlassian.seraph.auth.AuthenticationContextImpl;
7 import com.atlassian.seraph.SecurityService;
8 import com.atlassian.seraph.Initable;
9 import com.atlassian.seraph.cookie.CookieFactory;
10 import com.atlassian.seraph.util.XMLUtils;
11 import com.atlassian.seraph.controller.SecurityController;
12 import com.atlassian.seraph.interceptor.Interceptor;
13 import com.opensymphony.util.ClassLoaderUtil;
14 import org.apache.log4j.Category;
15 import org.w3c.dom.Element;
16 import org.w3c.dom.Node;
17 import org.w3c.dom.NodeList;
18
19 import javax.xml.parsers.DocumentBuilderFactory;
20 import java.io.Serializable;
21 import java.net.URL;
22 import java.util.*;
23
24
25
26
27
28
29 public class SecurityConfigImpl implements Serializable, SecurityConfig
30 {
31 private static final Category log = Category.getInstance(SecurityConfigImpl.class);
32 private static SecurityConfigImpl instance = null;
33
34 public static final String DEFAULT_CONFIG_LOCATION = "seraph-config.xml";
35
36 private String configFileLocation = "seraph-config.xml";
37 protected Authenticator authenticator = null;
38 protected RoleMapper roleMapper = null;
39 protected SecurityController controller;
40 protected List services = null;
41 protected List interceptors = null;
42
43 private String loginURL;
44 private String logoutURL;
45 private String originalURLKey = "seraph_originalurl";
46 private String cookieEncoding;
47 private String loginCookieKey = "seraph.os.cookie";
48 private String linkLoginURL;
49 private String authType;
50 private boolean insecureCookie;
51
52 private int autoLoginCookieAge = 365 * 24 * 60 * 60;
53
54 private LoginUrlStrategy loginUrlStrategy;
55 private String loginCookiePath;
56
57
58 public SecurityConfigImpl(String configFileLocation) throws ConfigurationException
59 {
60 if (configFileLocation != null)
61 {
62 this.configFileLocation = configFileLocation;
63 log.debug("Config file location passed. Location: " + this.configFileLocation);
64 }
65 else
66 {
67 log.debug("Initialising securityConfig using default configFile: " + this.configFileLocation);
68 }
69
70 init();
71 }
72
73 private void init() throws ConfigurationException
74 {
75 services = new ArrayList();
76 interceptors = new ArrayList();
77
78 try
79 {
80 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
81 URL fileUrl = ClassLoaderUtil.getResource(configFileLocation, this.getClass());
82
83 if (fileUrl == null)
84 throw new IllegalArgumentException("No such XML file: " + configFileLocation);
85
86
87 org.w3c.dom.Document doc = factory.newDocumentBuilder().parse(fileUrl.toString());
88 Element rootEl = doc.getDocumentElement();
89
90 configureParameters(rootEl);
91 configureAuthenticator(rootEl);
92 configureController(rootEl);
93 configureRoleMapper(rootEl);
94 configureServices(rootEl);
95 configureInterceptors(rootEl);
96 configureLoginUrlStrategy(rootEl);
97 CookieFactory.init(this);
98 }
99 catch (Exception e)
100 {
101 e.printStackTrace();
102 throw new ConfigurationException("Exception configuring from '"+configFileLocation+"': " + e);
103 }
104 }
105
106 protected void configureLoginUrlStrategy(Element rootEl) throws ConfigurationException
107 {
108 loginUrlStrategy = (LoginUrlStrategy) configureClass(rootEl, "login-url-strategy");
109
110 if (loginUrlStrategy == null)
111 {
112 loginUrlStrategy = new DefaultLoginUrlStrategy();
113 }
114 }
115
116 protected void configureAuthenticator(Element rootEl) throws ConfigurationException
117 {
118 authenticator = (Authenticator) configureClass(rootEl, "authenticator");
119
120 try
121 {
122 if (authenticator == null)
123 {
124 authenticator = (Authenticator) ClassLoaderUtil.loadClass(Authenticator.DEFAULT_AUTHENTICATOR, this.getClass()).newInstance();
125 authenticator.init(new HashMap(), this);
126 }
127 }
128 catch (Exception e)
129 {
130 throw new ConfigurationException("Could not lookup class: " + Authenticator.DEFAULT_AUTHENTICATOR + ":" + e);
131 }
132 }
133
134 protected void configureController(Element rootEl) throws ConfigurationException
135 {
136 controller = (SecurityController) configureClass(rootEl, "controller");
137
138 try
139 {
140 if (controller == null)
141 controller = (SecurityController) ClassLoaderUtil.loadClass(SecurityController.NULL_CONTROLLER, this.getClass()).newInstance();
142 }
143 catch (Exception e)
144 {
145 throw new ConfigurationException("Could not lookup class: " + SecurityController.NULL_CONTROLLER + ":" + e);
146 }
147 }
148
149 protected void configureRoleMapper(Element rootEl) throws ConfigurationException
150 {
151 roleMapper = (RoleMapper) configureClass(rootEl, "rolemapper");
152 }
153
154 private Initable configureClass(Element rootEl, String tagname) throws ConfigurationException
155 {
156 try
157 {
158 NodeList elementList = rootEl.getElementsByTagName(tagname);
159
160 for (int i = 0; i < elementList.getLength(); i++)
161 {
162 Element authEl = (Element) elementList.item(i);
163 String clazz = authEl.getAttribute("class");
164
165 Initable initable = (Initable) ClassLoaderUtil.loadClass(clazz, this.getClass()).newInstance();
166
167 Map params = getInitParameters(authEl);
168
169 initable.init(params, this);
170 return initable;
171 }
172 }
173 catch (Exception e)
174 {
175 throw new ConfigurationException("Could not create: " + tagname + ": " + e);
176 }
177
178 return null;
179 }
180
181 private void configureParameters(Element rootEl)
182 {
183 NodeList nl = rootEl.getElementsByTagName("parameters");
184 Element parametersEl = (Element) nl.item(0);
185 Map globalParams = getInitParameters(parametersEl);
186
187 loginURL = (String) globalParams.get("login.url");
188 linkLoginURL = (String) globalParams.get("link.login.url");
189 logoutURL = (String) globalParams.get("logout.url");
190
191 if (globalParams.get("original.url.key") != null)
192 originalURLKey = (String) globalParams.get("original.url.key");
193
194 if (globalParams.get("cookie.encoding") != null)
195 cookieEncoding = (String) globalParams.get("cookie.encoding");
196
197 if (globalParams.get("login.cookie.key") != null)
198 loginCookieKey = (String) globalParams.get("login.cookie.key");
199
200 if (globalParams.get("login.cookie.path") != null)
201 loginCookiePath = (String) globalParams.get("login.cookie.path");
202
203 if (globalParams.get("authentication.type") != null)
204 authType = (String) globalParams.get("authentication.type");
205
206 if (globalParams.get("autologin.cookie.age") != null)
207 autoLoginCookieAge = Integer.parseInt(globalParams.get("autologin.cookie.age").toString());
208
209 if (globalParams.get("insecure.cookie") != null)
210 insecureCookie = "true".equals(globalParams.get("insecure.cookie"));
211 }
212
213 private void configureServices(Element rootEl) throws ConfigurationException
214 {
215 NodeList nl = rootEl.getElementsByTagName("services");
216
217 if (nl != null && nl.getLength() > 0)
218 {
219 Element servicesEl = (Element) nl.item(0);
220 NodeList serviceList = servicesEl.getElementsByTagName("service");
221
222 for (int i = 0; i < serviceList.getLength(); i++)
223 {
224 Element serviceEl = (Element) serviceList.item(i);
225 String serviceClazz = serviceEl.getAttribute("class");
226
227 if (serviceClazz == null || "".equals(serviceClazz))
228 throw new ConfigurationException("Service element with bad class attribute");
229
230 try
231 {
232 log.debug("Adding seraph service of class: " + serviceClazz);
233 SecurityService service = (SecurityService) ClassLoaderUtil.loadClass(serviceClazz, this.getClass()).newInstance();
234
235 Map serviceParams = getInitParameters(serviceEl);
236
237 service.init(serviceParams, this);
238
239 services.add(service);
240 }
241 catch (Exception e)
242 {
243 e.printStackTrace();
244 throw new ConfigurationException("Could not getRequest service: " + serviceClazz + ". Exception: " + e);
245 }
246 }
247 }
248 }
249
250 protected void configureInterceptors(Element rootEl) throws ConfigurationException
251 {
252 NodeList nl = rootEl.getElementsByTagName("interceptors");
253
254 if (nl != null && nl.getLength() > 0)
255 {
256 Element interceptorsEl = (Element) nl.item(0);
257 NodeList interceptorList = interceptorsEl.getElementsByTagName("interceptor");
258
259 for (int i = 0; i < interceptorList.getLength(); i++)
260 {
261 Element interceptorEl = (Element) interceptorList.item(i);
262 String interceptorClazz = interceptorEl.getAttribute("class");
263
264 if (interceptorClazz == null || "".equals(interceptorClazz))
265
266 throw new ConfigurationException("Interceptor element with bad class attribute");
267
268 try
269 {
270 log.debug("Adding interceptor of class: " + interceptorClazz);
271 Interceptor interceptor = (Interceptor) ClassLoaderUtil.loadClass(interceptorClazz, this.getClass()).newInstance();
272
273 Map interceptorParams = getInitParameters(interceptorEl);
274
275 interceptor.init(interceptorParams, this);
276
277 interceptors.add(interceptor);
278 }
279 catch (Exception e)
280 {
281 e.printStackTrace();
282 throw new ConfigurationException("Could not getRequest service: " + interceptorClazz + ". Exception: " + e);
283 }
284 }
285 }
286 }
287
288 protected Map getInitParameters(Element el)
289 {
290 Map params = new HashMap();
291
292 NodeList nl = el.getElementsByTagName("init-param");
293
294 for (int i = 0; i < nl.getLength(); i++)
295 {
296 Node initParam = nl.item(i);
297 String paramName = XMLUtils.getContainedText(initParam, "param-name");
298 String paramValue = XMLUtils.getContainedText(initParam, "param-value");
299 params.put(paramName, paramValue);
300 }
301
302 return params;
303 }
304
305 public void destroy()
306 {
307 for (Iterator iterator = services.iterator(); iterator.hasNext();)
308 {
309 SecurityService securityService = (SecurityService) iterator.next();
310 securityService.destroy();
311 }
312
313 for (Iterator iterator = interceptors.iterator(); iterator.hasNext();)
314 {
315 ((Interceptor) iterator.next()).destroy();
316 }
317
318 return;
319 }
320
321 public void addInterceptor(Interceptor interceptor)
322 {
323 interceptors.add(interceptor);
324 }
325
326 public List getServices()
327 {
328 return services;
329 }
330
331 public String getLoginURL()
332 {
333 return loginUrlStrategy.getLoginURL(this, loginURL);
334 }
335
336 public String getLinkLoginURL()
337 {
338 return loginUrlStrategy.getLinkLoginURL(this, linkLoginURL);
339 }
340
341 public String getLogoutURL()
342 {
343 return loginUrlStrategy.getLogoutURL(this, logoutURL);
344 }
345
346 public String getOriginalURLKey()
347 {
348 return originalURLKey;
349 }
350
351 public Authenticator getAuthenticator()
352 {
353 return authenticator;
354 }
355
356 public AuthenticationContext getAuthenticationContext()
357 {
358 return new AuthenticationContextImpl();
359 }
360
361 public SecurityController getController()
362 {
363 return controller;
364 }
365
366
367
368
369 public static SecurityConfigImpl getInstance(String configFileLocation) throws ConfigurationException
370 {
371 instance = new SecurityConfigImpl(configFileLocation);
372 return instance;
373 }
374
375
376
377
378
379 public static SecurityConfig getInstance()
380 {
381 if (instance == null)
382 {
383 try
384 {
385 if (instance == null)
386 {
387 instance = new SecurityConfigImpl(DEFAULT_CONFIG_LOCATION);
388 }
389 }
390 catch (ConfigurationException e)
391 {
392 log.error("Could not configure SecurityConfigImpl instance: " + e, e);
393 }
394 }
395
396 return instance;
397 }
398
399 public RoleMapper getRoleMapper()
400 {
401 return roleMapper;
402 }
403
404 public List getInterceptors(Class desiredInterceptorClass)
405 {
406 List result = new ArrayList();
407
408 for (Iterator iterator = interceptors.iterator(); iterator.hasNext();)
409 {
410 Interceptor interceptor = (Interceptor) iterator.next();
411
412 if (desiredInterceptorClass.isAssignableFrom(interceptor.getClass()))
413 {
414 result.add(interceptor);
415 }
416 }
417
418 return result;
419 }
420
421 public String getCookieEncoding()
422 {
423 return cookieEncoding;
424 }
425
426 public String getLoginCookiePath()
427 {
428 return loginCookiePath;
429 }
430
431 public String getLoginCookieKey()
432 {
433 return loginCookieKey;
434 }
435
436 public String getAuthType()
437 {
438 return authType;
439 }
440
441 public boolean isInsecureCookie()
442 {
443 return insecureCookie;
444 }
445
446 public int getAutoLoginCookieAge()
447 {
448 return autoLoginCookieAge;
449 }
450 }