1 /* 2 * JBoss, Home of Professional Open Source 3 * Copyright 2005, JBoss Inc., and individual contributors as indicated 4 * by the @authors tag. See the copyright.txt in the distribution for a 5 * full listing of individual contributors. 6 * 7 * This is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU Lesser General Public License as 9 * published by the Free Software Foundation; either version 2.1 of 10 * the License, or (at your option) any later version. 11 * 12 * This software is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this software; if not, write to the Free 19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 */ 22 package javax.security.auth.message.config; 23 24 import java.security.AccessController; 25 import java.security.PrivilegedActionException; 26 import java.security.PrivilegedExceptionAction; 27 import java.security.SecurityPermission; 28 import java.util.Map; 29 30 import javax.security.auth.message.AuthException; 31 32 33 //$Id: AuthConfigFactory.java 64016 2007-07-12 21:12:52Z anil.saldhana@jboss.com $ 34 35 /** 36 * <p>This class is used to obtain AuthConfigProvider objects that can be used to 37 * obtain authentication context configuration objects, i.e., ClientAuthConfig and 38 * ServerAuthConfig objects. Authentication context configuration objects are used 39 * to obtain authentication context objects. Authentication context objects, 40 * i.e., ClientAuthContext and ServerAuthContex objects encapsulate authentication 41 * modules. Authentication modules are pluggable components that perform 42 * security-related processing of request and response messages.</p> 43 * <p>Callers do not operate on modules directly. Instead they rely on an authentication 44 * context to manage the invocation of modules. A caller obtains an authentication 45 * context by calling the getAuthContext method on a ClientAuthConfig or ServerAuthConfig 46 * obtained from an AuthConfigProvider.</p> 47 * <p>The following represents a typical sequence of calls for obtaining a client 48 * authentication context, and then using it to secure a request.</p> 49 * <ol> 50 * <li>AuthConfigFactory factory = AuthConfigFactory.getFactory();</li> 51 * <li>AuthConfigProvider provider = factory.getConfigProvider(layer,appID,null);</li> 52 * <li>ClientAuthConfig config = provider.getClientAuthConfig(layer,appID,cbh)</li> 53 * <li>String operation = config.getOperation(authParam);</li> 54 * <li>ClientAuthContext context = config.getAuthContext(operation,properties);</li> 55 * <li>context.secureRequest(authParam,subject,...);</li> 56 * </ol> 57 * <p>A system-wide AuthConfigFactory implementation can be set by invoking 58 * setFactory, and retrieved via getFactory.</p> 59 * <p>Every implementation of this abstract class must offer a public, zero argument 60 * constructor. This constructor must support the construction and registration of 61 * AuthConfigProviders from a persistent declarative representation.</p> 62 * <p>For example, a factory implementation class could interpret the contents of a 63 * file containing a sequence of configuration entries, with one entry per 64 * AuthConfigProvider, with each entry representing the following 5 values:</p> 65 * <ul> 66 * <li>the fully qualified name of the provider implementation class</li> 67 * <li>the pathname of the provider initialization file</li> 68 * <li>the message layer name</li> 69 * <li>the application context identifier</li> 70 * <li>the registration description</li> 71 * </ul> 72 * <p>A value would be required for the implementation class. The remaining values 73 * could be optional, and when specified, the contents of the provider initialization 74 * file could be required to conform to the syntax defined by 75 * <a href="http://java.sun.com/dtd/properties.dtd">http://java.sun.com/dtd/properties.dtd</a> 76 * (which can be loaded into a Properties object).</p> 77 * 78 * @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a> 79 * @author Charlie Lai, Ron Monzillo (Javadoc for JSR-196)</a> 80 * @since May 12, 2006 81 * @version $Revision: 64016 $ 82 */ 83 public abstract class AuthConfigFactory 84 { 85 private static AuthConfigFactory _factory = null; 86 private static final String FACTORY_PROP = "authconfigprovider.factory"; 87 88 /** The default AuthConfigFactory implementation */ 89 static final String DEFAULT_FACTORY_SECURITY_PROPERTY = 90 "org.jboss.security.auth.message.config.JBossAuthConfigFactory"; 91 92 public AuthConfigFactory() 93 { 94 } 95 96 /** 97 * Disassociate the listener from all the provider registrations whose layer and 98 * appContext values are matched by the corresponding arguments to this method. 99 * 100 * @param listener the RegistrationListener to be detached. 101 * @param layer a String identifying the message layer or null. 102 * @param appContext a String value identifying the application contex or null. 103 * @return 104 */ 105 public abstract String[] detachListener(RegistrationListener listener, String layer, 106 String appContext); 107 108 /** 109 * Get a registered AuthConfigProvider from the factory. Get the provider of 110 * ServerAuthConfig and/or ClientAuthConfig objects registered for the identified 111 * message layer and application context. 112 * 113 * @param layer a String identifying the message layer for which the registered 114 * AuthConfigProvider is to be returned. This argument may be null. 115 * @param appContext a String that identifys the application messaging context for 116 * which the registered AuthConfigProvider is to be returned. This 117 * argument may be null. 118 * @param listener the RegistrationListener whose notify method is to be invoked 119 * if the corresponding registration is unregistered or replaced. The 120 * value of this argument may be null. 121 * @return the implementation of the AuthConfigProvider interface registered at the 122 * factory for the layer and appContext or null if no AuthConfigProvider 123 * is selected. 124 * <p>All factories shall employ the following precedence rules to select 125 * the registered AuthConfigProvider that matches the layer and appContext 126 * arguments:</p> 127 * <ul> 128 * <li>The provider that is specifically registered for both the corresponding 129 * message layer and appContext shall be selected.</li> 130 * <li>if no provider is selected according to the preceding rule, the provider 131 * specifically registered for the corresponding appContext and for all message 132 * layers shall be selected.</li> 133 * <li>if no provider is selected according to the preceding rules, the provider 134 * specifically registered for the corresponding message layer and for all 135 * appContexts shall be selected.</li> 136 * <li>if no provider is selected according to the preceding rules, the provider 137 * registered for all message layers and for all appContexts shall be selected.</li> 138 * <li>if no provider is selected according to the preceding rules, the factory 139 * shall terminate its search for a registered provider.</li> 140 */ 141 public abstract AuthConfigProvider getConfigProvider( String layer, 142 String appContext, RegistrationListener listener); 143 144 /** 145 * <p>Get the system-wide AuthConfigFactory implementation.</p> 146 * <p>If a non-null system-wide factory instance is defined at the time of the call, 147 * e.g., with setfactory, it will be returned. Otherwise, an attempt will be made to 148 * construct an instance of the default AuthConfigFactory implementation class. The 149 * fully qualified class name of the default factory implementation class is obtained 150 * from the value of the ?authconfigprovider.factory? security property. When an 151 * instance of the defaultfactory implementation class is successfully constructed by 152 * this method, this method will set it as the system-wide factory instance.</p> 153 * 154 * @return the non-null system-wide AuthConfigFactory instance set at the time of the 155 * call, or if that value was null, the value of the system-wide factory 156 * instance established by this method. This method returns null when the 157 * system-wide factory was not defined when this method was called and no 158 * default factory name was defined via the security property. 159 */ 160 public static AuthConfigFactory getFactory() 161 { 162 //Validate the caller permission 163 SecurityManager sm = System.getSecurityManager(); 164 if (sm != null) 165 sm.checkPermission(new SecurityPermission("getFactory")); 166 167 if (_factory == null) 168 { 169 String factoryName = null; 170 Class clazz = null; 171 try 172 { 173 LoadAction action = new LoadAction(); 174 try 175 { 176 clazz = (Class) AccessController.doPrivileged(action); 177 factoryName = action.getName(); 178 } 179 catch (PrivilegedActionException ex) 180 { 181 factoryName = action.getName(); 182 Exception e = ex.getException(); 183 if (e instanceof ClassNotFoundException) 184 throw (ClassNotFoundException) e; 185 else 186 throw new IllegalStateException("Failure during load of class: " + action.getName() + e); 187 } 188 _factory = (AuthConfigFactory) clazz.newInstance(); 189 } 190 catch (ClassNotFoundException e) 191 { 192 String msg = "Failed to find AuthConfigFactory : " + factoryName; 193 IllegalStateException ise = new IllegalStateException(msg); 194 ise.initCause(e); 195 throw ise; 196 } 197 catch (IllegalAccessException e) 198 { 199 String msg = "Unable to access class : " + factoryName; 200 IllegalStateException ise = new IllegalStateException(msg); 201 ise.initCause(e); 202 throw ise; 203 } 204 catch (InstantiationException e) 205 { 206 String msg = "Failed to create instance of: " + factoryName; 207 IllegalStateException ise = new IllegalStateException(msg); 208 ise.initCause(e); 209 throw ise; 210 } 211 catch (ClassCastException e) 212 { 213 StringBuffer msg = new StringBuffer(factoryName + " Is not a AuthConfigFactory, "); 214 msg.append("ACF.class.CL: "+ AuthConfigFactory.class.getClassLoader()); 215 msg.append("\nACF.class.CS: " + AuthConfigFactory.class.getProtectionDomain().getCodeSource()); 216 msg.append("\nACF.class.hash: "+System.identityHashCode(AuthConfigFactory.class)); 217 msg.append("\nclazz.CL: "+clazz.getClassLoader()); 218 msg.append("\nclazz.CS: "+clazz.getProtectionDomain().getCodeSource()); 219 msg.append("\nclazz.super.CL: "+clazz.getSuperclass().getClassLoader()); 220 msg.append("\nclazz.super.CS: "+clazz.getSuperclass().getProtectionDomain().getCodeSource()); 221 msg.append("\nclazz.super.hash: "+System.identityHashCode(clazz.getSuperclass())); 222 ClassCastException cce = new ClassCastException(msg.toString()); 223 cce.initCause(e); 224 throw cce; 225 } 226 } 227 return _factory; 228 } 229 230 public abstract RegistrationContext getRegistrationContext(String registrationID); 231 232 public abstract String[] getRegistrationIDs(AuthConfigProvider provider); 233 234 public abstract void refresh() throws AuthException, SecurityException; 235 236 public abstract String registerConfigProvider( String className, Map properties,String layer, 237 String appContext, String description) throws AuthException, SecurityException; 238 239 public abstract java.lang.String registerConfigProvider(AuthConfigProvider provider, 240 String layer, String appContext, String description); 241 242 public abstract boolean removeRegistration( String registrationID); 243 244 public static void setFactory(AuthConfigFactory factory) 245 { 246 _factory = factory; 247 } 248 249 /** 250 * Represents the layer identifier, application context identifier., and description 251 * components of an AuthConfigProvider registration at the factory 252 */ 253 public static interface RegistrationContext 254 { 255 /** 256 * Get the application context identifier from the registration context 257 * 258 * @return a String identifying the application context for which the 259 * AuthConfigProvider was registered. The returned value may be null. 260 */ 261 String getAppContext(); 262 263 /** 264 * Get the description from the registration context 265 * 266 * @return the description String from the registration, or null, if no 267 * description string was included in the registration. 268 */ 269 String getDescription(); 270 271 /** 272 * Get the layer name from the registration context 273 * @return a String identifying the message layer for which the AuthConfigProvider 274 * was registered. the returned value may be null. 275 */ 276 String getMessageLayer(); 277 278 public boolean isPersistent(); 279 } 280 281 282 283 /** A PrivilegedExceptionAction that looks up the class name identified 284 * by the authcontextfactory.provider system property and loads the class 285 * using the thread context class loader. 286 */ 287 private static class LoadAction implements PrivilegedExceptionAction 288 { 289 private String name; 290 public String getName() 291 { 292 return name; 293 } 294 public Object run() 295 throws Exception 296 { 297 name = System.getProperty(FACTORY_PROP); 298 if( name == null ) 299 { 300 // Use the default factory impl 301 name = DEFAULT_FACTORY_SECURITY_PROPERTY; 302 } 303 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 304 Class factoryClass = loader.loadClass(name); 305 return factoryClass; 306 } 307 } 308 }