/AuthenticRoast/AuthenticRoast-Impl/src/main/java/name/aikesommer/authenticator/RegistryImpl.java

http://authenticroast.googlecode.com/ · Java · 242 lines · 140 code · 29 blank · 73 comment · 37 complexity · 1180539aaa77c94304c7df80278b2c13 MD5 · raw file

  1. /**
  2. * Copyright (C) 2007-2010 Aike J Sommer (http://aikesommer.name/)
  3. *
  4. * This file is part of AuthenticRoast.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General
  17. * Public License along with this library; if not, write to the
  18. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  19. * Boston, MA 02110-1301 USA
  20. *
  21. * You can reach the author and get more information about this
  22. * project at: http://aikesommer.name/
  23. */
  24. package name.aikesommer.authenticator;
  25. import java.util.logging.Level;
  26. import java.util.logging.Logger;
  27. import javax.servlet.ServletContext;
  28. /**
  29. * Allows web-applications to register a PluggableAuthenticator to use
  30. * for requests to its resources.
  31. * You can also specify the class as init-parameter
  32. * <code>roast.authenticator.class</code>.
  33. *
  34. * @author Aike J Sommer
  35. */
  36. public class RegistryImpl extends Registry {
  37. private static final String AUTHENTICATOR_NOTE = RegistryImpl.class.getName() + ".AUTHENTICATOR";
  38. private static final String CROSS_CONTEXT_NOTE = RegistryImpl.class.getName() + ".CROSS_CONTEXT";
  39. private static final String PRINCIPALSTORE_FACTORY_NOTE = RegistryImpl.class.getName()
  40. + ".PRINCIPALSTORE_FACTORY";
  41. private static final String PRINCIPALSTORE_NOTE = RegistryImpl.class.getName()
  42. + ".PRINCIPALSTORE";
  43. private static ClassLoaderResolver resolver = null;
  44. /**
  45. * Create or find an instance that will use context to store the
  46. * authenticator.
  47. *
  48. * @param context The ServletContext instance for the current web-app.
  49. */
  50. public static RegistryImpl forContext(ServletContext context) {
  51. return new RegistryImpl(context);
  52. }
  53. protected static void setResolver(ClassLoaderResolver resolver) {
  54. RegistryImpl.resolver = resolver;
  55. }
  56. private ServletContext context;
  57. /**
  58. * Create an instance that will use context to store the authenticator
  59. * class.
  60. *
  61. * @param context The ServletContext instance for the current web-app.
  62. */
  63. public RegistryImpl(ServletContext context) {
  64. this.context = context;
  65. }
  66. /**
  67. * Register a as authenticator for this Web-App.
  68. *
  69. * @param a The PluggableAuthenticator to use for this web-app.
  70. */
  71. public void register(PluggableAuthenticator a) {
  72. context.setAttribute(AUTHENTICATOR_NOTE, a);
  73. }
  74. /**
  75. * Register f as principal-store factory for this Web-App.
  76. *
  77. * @param s The PrincipalStore.Factory to use for this web-app.
  78. */
  79. public void register(PrincipalStore.Factory f) {
  80. context.setAttribute(PRINCIPALSTORE_FACTORY_NOTE, f);
  81. }
  82. /**
  83. * This will be called by the AuthModule to create the authenticator
  84. * instance.
  85. *
  86. * @return A PluggableAuthenticator instance from the previously registered
  87. * class.
  88. */
  89. protected PluggableAuthenticator authenticator() {
  90. try {
  91. PluggableAuthenticator authenticator = (PluggableAuthenticator) context.getAttribute(
  92. AUTHENTICATOR_NOTE);
  93. if (authenticator == null) {
  94. String className = context.getInitParameter("roast.authenticator.class");
  95. if (className != null) {
  96. Class<? extends PluggableAuthenticator> c = null;
  97. if (resolver != null) {
  98. try {
  99. c = (Class<? extends PluggableAuthenticator>) resolver.resolve(context).loadClass(
  100. className);
  101. } catch (ClassNotFoundException ex) {
  102. }
  103. }
  104. if (c == null) {
  105. try {
  106. c = (Class<? extends PluggableAuthenticator>) Thread.currentThread().getContextClassLoader().loadClass(
  107. className);
  108. } catch (ClassNotFoundException ex) {
  109. c = (Class<? extends PluggableAuthenticator>) Class.forName(className);
  110. }
  111. }
  112. authenticator = c.newInstance();
  113. } else {
  114. String delegateName = context.getInitParameter("roast.delegate");
  115. if (delegateName != null) {
  116. ServletContext delegate = context.getContext(delegateName);
  117. if (delegate == null) {
  118. throw new IllegalArgumentException("The context '" + delegateName
  119. + "' does not exist!");
  120. }
  121. RegistryImpl delegateRegistry = RegistryImpl.forContext(delegate);
  122. if (delegateRegistry.isDelegate()) {
  123. authenticator = new DelegatingAuthenticator(
  124. delegateRegistry.authenticator(), delegate);
  125. } else {
  126. throw new IllegalArgumentException("The context '" + delegateName
  127. + "' does not allow to be used as a delegate!");
  128. }
  129. }
  130. }
  131. if (authenticator != null) {
  132. register(authenticator);
  133. }
  134. }
  135. return authenticator;
  136. } catch (Throwable t) {
  137. Logger log = Logger.getLogger(getClass().getName());
  138. log.severe("failed to create authenticator: " + t);
  139. log.log(Level.FINE, "failed to create authenticator", t);
  140. return null;
  141. }
  142. }
  143. /**
  144. * Get wether cross-context authentication should be enabled.
  145. */
  146. protected boolean isCrossContext() {
  147. Boolean result = (Boolean) context.getAttribute(CROSS_CONTEXT_NOTE);
  148. if (result == null) {
  149. result = context.getInitParameter("roast.delegate") != null || isDelegate();
  150. }
  151. result = result == null ? false : result;
  152. context.setAttribute(CROSS_CONTEXT_NOTE, result);
  153. return result;
  154. }
  155. /**
  156. * Get wether this context allows to be used as a delegate.
  157. */
  158. private boolean isDelegate() {
  159. return "true".equals(context.getInitParameter("roast.is-delegate"));
  160. }
  161. /**
  162. * This will be called by the AuthModule to create the principal-store
  163. * instance.
  164. *
  165. * @return A PrincipalStore instance from the previously registered
  166. * class.
  167. */
  168. protected PrincipalStore principalStore() {
  169. ThreadLocal<PrincipalStore> stores = (ThreadLocal<PrincipalStore>) context.getAttribute(
  170. PRINCIPALSTORE_NOTE);
  171. if (stores != null) {
  172. return stores.get();
  173. }
  174. return null;
  175. }
  176. protected void createPrincipalStore(AuthenticationRequest request) {
  177. ThreadLocal<PrincipalStore> stores = (ThreadLocal<PrincipalStore>) context.getAttribute(
  178. PRINCIPALSTORE_NOTE);
  179. if (stores == null) {
  180. stores = new ThreadLocal<PrincipalStore>();
  181. context.setAttribute(PRINCIPALSTORE_NOTE, stores);
  182. }
  183. stores.remove();
  184. PrincipalStore store = null;
  185. try {
  186. PrincipalStore.Factory factory = (PrincipalStore.Factory) context.getAttribute(
  187. PRINCIPALSTORE_FACTORY_NOTE);
  188. if (factory == null) {
  189. String name = context.getInitParameter("roast.principal-store.factory");
  190. if (name == null) {
  191. store = isCrossContext() ?
  192. new CrossContextPrincipalStore(request.getHttpServletRequest(), request.getHttpServletResponse()) :
  193. new DefaultPrincipalStore(request.getHttpServletRequest().getSession());
  194. } else {
  195. Class<? extends PrincipalStore.Factory> c = (Class<? extends PrincipalStore.Factory>) Class.forName(
  196. name);
  197. factory = c.newInstance();
  198. register(factory);
  199. }
  200. }
  201. if (store == null && factory != null) {
  202. store = factory.factory(request);
  203. }
  204. } catch (Throwable t) {
  205. Logger log = Logger.getLogger(getClass().getName());
  206. log.severe("failed to create principal-store: " + t);
  207. log.log(Level.FINE, "failed to create principal-store", t);
  208. }
  209. if (store != null) {
  210. stores.set(store);
  211. }
  212. }
  213. }