| /* |
| * Copyright (c) 2022 Contributors to the Eclipse Foundation |
| * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| package com.sun.enterprise.security.jmac.config; |
| |
| import java.io.IOException; |
| import java.lang.reflect.Constructor; |
| import java.security.AccessController; |
| import java.security.Principal; |
| import java.security.PrivilegedAction; |
| import java.security.PrivilegedActionException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.locks.ReadWriteLock; |
| import java.util.concurrent.locks.ReentrantReadWriteLock; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import javax.security.auth.Subject; |
| import javax.security.auth.callback.Callback; |
| import javax.security.auth.callback.CallbackHandler; |
| |
| import org.glassfish.internal.api.Globals; |
| |
| import com.sun.enterprise.deployment.runtime.common.MessageSecurityBindingDescriptor; |
| import com.sun.enterprise.deployment.runtime.web.SunWebApp; |
| |
| // types to support backward compatability of pre-standard 196 auth modules |
| |
| import com.sun.enterprise.security.jauth.AuthParam; |
| import com.sun.enterprise.security.jauth.AuthPolicy; |
| import com.sun.enterprise.security.jauth.FailureException; |
| import com.sun.enterprise.security.jauth.HttpServletAuthParam; |
| import com.sun.enterprise.security.jauth.PendingException; |
| import com.sun.enterprise.security.jmac.AuthMessagePolicy; |
| import com.sun.enterprise.security.jmac.WebServicesDelegate; |
| import com.sun.logging.LogDomains; |
| |
| // jsr 196 interface types |
| import jakarta.security.auth.message.AuthException; |
| import jakarta.security.auth.message.AuthStatus; |
| import jakarta.security.auth.message.MessageInfo; |
| import jakarta.security.auth.message.MessagePolicy; |
| import jakarta.security.auth.message.callback.CallerPrincipalCallback; |
| import jakarta.security.auth.message.config.AuthConfig; |
| import jakarta.security.auth.message.config.AuthConfigFactory; |
| import jakarta.security.auth.message.config.AuthConfigProvider; |
| import jakarta.security.auth.message.config.ClientAuthConfig; |
| import jakarta.security.auth.message.config.ClientAuthContext; |
| import jakarta.security.auth.message.config.ServerAuthConfig; |
| import jakarta.security.auth.message.config.ServerAuthContext; |
| import jakarta.security.auth.message.module.ClientAuthModule; |
| import jakarta.security.auth.message.module.ServerAuthModule; |
| |
| /** |
| * This class implements the interface AuthConfigProvider. |
| * |
| * @author Shing Wai Chan |
| * @author Ronald Monzillo |
| */ |
| public class GFServerConfigProvider implements AuthConfigProvider { |
| |
| public static final String SOAP = "SOAP"; |
| public static final String HTTPSERVLET = "HttpServlet"; |
| |
| protected static final String CLIENT = "client"; |
| protected static final String SERVER = "server"; |
| protected static final String MANAGES_SESSIONS_OPTION = "managessessions"; |
| |
| private static Logger logger = LogDomains.getLogger(GFServerConfigProvider.class, LogDomains.SECURITY_LOGGER); |
| private static final String DEFAULT_HANDLER_CLASS = "com.sun.enterprise.security.jmac.callback.ContainerCallbackHandler"; |
| private static final String DEFAULT_PARSER_CLASS = "com.sun.enterprise.security.jmac.config.ConfigDomainParser"; |
| |
| // since old api does not have subject in PasswordValdiationCallback, |
| // this is for old modules to pass group info back to subject |
| private static final ThreadLocal<Subject> subjectLocal = new ThreadLocal<>(); |
| |
| protected static final ReadWriteLock rwLock = new ReentrantReadWriteLock(); |
| protected static final Map<String, String> layerDefaultRegisIDMap = new HashMap<>(); |
| |
| // mutable statics should be kept package private to eliminate |
| // the ability for subclasses to access them |
| static int epoch; |
| static String parserClassName = null; |
| static ConfigParser parser; |
| static boolean parserInitialized = false; |
| static AuthConfigFactory slaveFactory = null; |
| |
| // keep the slave from being visible outside |
| static AuthConfigProvider slaveProvider = null; |
| |
| protected AuthConfigFactory factory = null; |
| private WebServicesDelegate wsdelegate = null; |
| |
| public GFServerConfigProvider(Map<String, String> properties, AuthConfigFactory factory) { |
| this.factory = factory; |
| initializeParser(); |
| |
| if (factory != null) { |
| boolean hasSlaveFactory = false; |
| try { |
| rwLock.readLock().lock(); |
| hasSlaveFactory = slaveFactory != null; |
| } finally { |
| rwLock.readLock().unlock(); |
| } |
| |
| if (!hasSlaveFactory) { |
| try { |
| rwLock.writeLock().lock(); |
| if (slaveFactory == null) { |
| slaveFactory = factory; |
| } |
| } finally { |
| rwLock.writeLock().unlock(); |
| } |
| } |
| } |
| |
| boolean hasSlaveProvider = false; |
| try { |
| rwLock.readLock().lock(); |
| hasSlaveProvider = slaveProvider != null; |
| } finally { |
| rwLock.readLock().unlock(); |
| } |
| |
| if (!hasSlaveProvider) { |
| try { |
| rwLock.writeLock().lock(); |
| if (slaveProvider == null) { |
| slaveProvider = this; |
| } |
| } finally { |
| rwLock.writeLock().unlock(); |
| } |
| } |
| wsdelegate = Globals.get(WebServicesDelegate.class); |
| } |
| |
| private void initializeParser() { |
| try { |
| rwLock.readLock().lock(); |
| if (parserInitialized) { |
| return; |
| } |
| } finally { |
| rwLock.readLock().unlock(); |
| } |
| |
| try { |
| rwLock.writeLock().lock(); |
| if (!parserInitialized) { |
| parserClassName = System.getProperty("config.parser", DEFAULT_PARSER_CLASS); |
| loadParser(this, factory, null); |
| parserInitialized = true; |
| } |
| } finally { |
| rwLock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Instantiate+initialize module class |
| */ |
| static ModuleInfo createModuleInfo(Entry entry, CallbackHandler handler, String type, Map properties) throws AuthException { |
| try { |
| // instantiate module using no-arg constructor |
| Object newModule = entry.newInstance(); |
| |
| Map map = properties; |
| Map entryOptions = entry.getOptions(); |
| |
| if (entryOptions != null) { |
| if (map == null) { |
| map = new HashMap(); |
| } else { |
| map = new HashMap(map); |
| } |
| map.putAll(entryOptions); |
| } |
| |
| // no doPrivilege at this point, need to revisit |
| if (SERVER.equals(type)) { |
| if (newModule instanceof ServerAuthModule) { |
| ServerAuthModule sam = (ServerAuthModule) newModule; |
| sam.initialize(entry.getRequestPolicy(), entry.getResponsePolicy(), handler, map); |
| } else if (newModule instanceof com.sun.enterprise.security.jauth.ServerAuthModule) { |
| |
| com.sun.enterprise.security.jauth.ServerAuthModule sam0 = (com.sun.enterprise.security.jauth.ServerAuthModule) newModule; |
| |
| AuthPolicy requestPolicy = entry.getRequestPolicy() != null ? new AuthPolicy(entry.getRequestPolicy()) : null; |
| |
| AuthPolicy responsePolicy = entry.getResponsePolicy() != null ? new AuthPolicy(entry.getResponsePolicy()) : null; |
| |
| sam0.initialize(requestPolicy, responsePolicy, handler, map); |
| } |
| } else if (newModule instanceof ClientAuthModule) { |
| ClientAuthModule cam = (ClientAuthModule) newModule; |
| cam.initialize(entry.getRequestPolicy(), entry.getResponsePolicy(), handler, map); |
| } else if (newModule instanceof com.sun.enterprise.security.jauth.ClientAuthModule) { |
| |
| com.sun.enterprise.security.jauth.ClientAuthModule cam0 = (com.sun.enterprise.security.jauth.ClientAuthModule) newModule; |
| |
| AuthPolicy requestPolicy = new AuthPolicy(entry.getRequestPolicy()); |
| |
| AuthPolicy responsePolicy = new AuthPolicy(entry.getResponsePolicy()); |
| |
| cam0.initialize(requestPolicy, responsePolicy, handler, map); |
| } |
| |
| return new ModuleInfo(newModule, map); |
| } catch (Exception e) { |
| if (e instanceof AuthException) { |
| throw (AuthException) e; |
| } |
| AuthException ae = new AuthException(); |
| ae.initCause(e); |
| throw ae; |
| } |
| } |
| |
| /** |
| * Create an object of a given class. |
| * |
| * @param className |
| * |
| */ |
| private static Object createObject(final String className) { |
| final ClassLoader loader = getClassLoader(); |
| if (System.getSecurityManager() != null) { |
| try { |
| return AccessController.doPrivileged(new PrivilegedExceptionAction() { |
| @Override |
| public Object run() throws Exception { |
| Class c = Class.forName(className, true, loader); |
| return c.newInstance(); |
| } |
| }); |
| } catch (PrivilegedActionException pae) { |
| throw new RuntimeException(pae.getException()); |
| } |
| } |
| try { |
| Class c = Class.forName(className, true, loader); |
| return c.newInstance(); |
| } catch (Throwable t) { |
| throw new RuntimeException(t); |
| } |
| } |
| |
| Entry getEntry(String intercept, String id, MessagePolicy requestPolicy, MessagePolicy responsePolicy, String type) { |
| |
| // get the parsed module config and DD information |
| |
| Map configMap; |
| |
| try { |
| rwLock.readLock().lock(); |
| configMap = parser.getConfigMap(); |
| } finally { |
| rwLock.readLock().unlock(); |
| } |
| |
| if (configMap == null) { |
| return null; |
| } |
| |
| // get the module config info for this intercept |
| |
| InterceptEntry intEntry = (InterceptEntry) configMap.get(intercept); |
| if (intEntry == null || intEntry.idMap == null) { |
| if (logger.isLoggable(Level.FINE)) { |
| logger.fine("module config has no IDs configured for [" + intercept + "]"); |
| } |
| return null; |
| } |
| |
| // look up the DD's provider ID in the module config |
| |
| IDEntry idEntry = null; |
| if (id == null || (idEntry = (IDEntry) intEntry.idMap.get(id)) == null) { |
| |
| // either the DD did not specify a provider ID, |
| // or the DD-specified provider ID was not found |
| // in the module config. |
| // |
| // in either case, look for a default ID in the module config |
| |
| if (logger.isLoggable(Level.FINE)) { |
| logger.fine("DD did not specify ID, " + "or DD-specified ID for [" + intercept + "] not found in config -- " |
| + "attempting to look for default ID"); |
| } |
| |
| String defaultID; |
| if (CLIENT.equals(type)) { |
| defaultID = intEntry.defaultClientID; |
| } else { |
| defaultID = intEntry.defaultServerID; |
| } |
| |
| idEntry = (IDEntry) intEntry.idMap.get(defaultID); |
| if (idEntry == null) { |
| |
| // did not find a default provider ID |
| |
| if (logger.isLoggable(Level.FINE)) { |
| logger.fine("no default config ID for [" + intercept + "]"); |
| } |
| return null; |
| } |
| } |
| |
| // we found the DD provider ID in the module config |
| // or we found a default module config |
| |
| // check provider-type |
| if (idEntry.type.indexOf(type) < 0) { |
| if (logger.isLoggable(Level.FINE)) { |
| logger.fine("request type [" + type + "] does not match config type [" + idEntry.type + "]"); |
| } |
| return null; |
| } |
| |
| // check whether a policy is set |
| MessagePolicy reqP = requestPolicy != null || responsePolicy != null ? requestPolicy : idEntry.requestPolicy; // default; |
| |
| MessagePolicy respP = requestPolicy != null || responsePolicy != null ? responsePolicy : idEntry.responsePolicy; // default; |
| |
| // optimization: if policy was not set, return null |
| if (reqP == null && respP == null) { |
| if (logger.isLoggable(Level.FINE)) { |
| logger.fine("no policy applies"); |
| } |
| return null; |
| } |
| |
| // return the configured modules with the correct policies |
| |
| Entry entry = new Entry(idEntry.moduleClassName, reqP, respP, idEntry.options); |
| |
| if (logger.isLoggable(Level.FINE)) { |
| logger.fine("getEntry for: " + intercept + " -- " + id + "\n module class: " + entry.moduleClassName + "\n options: " |
| + entry.options + "\n request policy: " + entry.requestPolicy + "\n response policy: " + entry.responsePolicy); |
| } |
| |
| return entry; |
| } |
| |
| /** |
| * Class representing a single AuthModule entry configured for an ID, interception point, and stack. |
| * |
| * <p> |
| * This class also provides a way for a caller to obtain an instance of the module listed in the entry by invoking the |
| * <code>newInstance</code> method. |
| */ |
| static class Entry { |
| |
| // for loading modules |
| private static final Class[] PARAMS = {}; |
| private static final Object[] ARGS = {}; |
| |
| private final String moduleClassName; |
| private final MessagePolicy requestPolicy; |
| private final MessagePolicy responsePolicy; |
| private final Map options; |
| |
| /** |
| * Construct a ConfigFile entry. |
| * |
| * <p> |
| * An entry encapsulates a single module and its related information. |
| * |
| * @param moduleClassName the module class name |
| * @param requestPolicy the request policy assigned to the module listed in this entry, which may be null. |
| * |
| * @param responsePolicy the response policy assigned to the module listed in this entry, which may be null. |
| * |
| * @param options the options configured for this module. |
| */ |
| Entry(String moduleClassName, MessagePolicy requestPolicy, MessagePolicy responsePolicy, Map options) { |
| this.moduleClassName = moduleClassName; |
| this.requestPolicy = requestPolicy; |
| this.responsePolicy = responsePolicy; |
| this.options = options; |
| } |
| |
| /** |
| * Return the request policy assigned to this module. |
| * |
| * @return the policy, which may be null. |
| */ |
| MessagePolicy getRequestPolicy() { |
| return requestPolicy; |
| } |
| |
| /** |
| * Return the response policy assigned to this module. |
| * |
| * @return the policy, which may be null. |
| */ |
| MessagePolicy getResponsePolicy() { |
| return responsePolicy; |
| } |
| |
| String getModuleClassName() { |
| return moduleClassName; |
| } |
| |
| Map getOptions() { |
| return options; |
| } |
| |
| /** |
| * Return a new instance of the module contained in this entry. |
| * |
| * <p> |
| * The default implementation of this method attempts to invoke the default no-args constructor of the module class. |
| * This method may be overridden if a different constructor should be invoked. |
| * |
| * @return a new instance of the module contained in this entry. |
| * |
| * @exception AuthException if the instantiation failed. |
| */ |
| Object newInstance() throws AuthException { |
| try { |
| final ClassLoader finalLoader = getClassLoader(); |
| Class c = Class.forName(moduleClassName, true, finalLoader); |
| Constructor constructor = c.getConstructor(PARAMS); |
| return constructor.newInstance(ARGS); |
| } catch (Exception e) { |
| if (logger.isLoggable(Level.WARNING)) { |
| logger.log(Level.WARNING, "jmac.provider_unable_to_load_authmodule", new String[] { moduleClassName, e.toString() }); |
| } |
| |
| AuthException ae = new AuthException(); |
| ae.initCause(e); |
| throw ae; |
| } |
| } |
| } |
| |
| public static class InterceptEntry { |
| String defaultClientID; |
| String defaultServerID; |
| HashMap idMap; |
| |
| public InterceptEntry(String defaultClientID, String defaultServerID, HashMap idMap) { |
| this.defaultClientID = defaultClientID; |
| this.defaultServerID = defaultServerID; |
| this.idMap = idMap; |
| } |
| |
| public HashMap getIdMap() { |
| return idMap; |
| } |
| |
| public void setIdMap(HashMap map) { |
| idMap = map; |
| } |
| |
| public String getDefaultClientID() { |
| return defaultClientID; |
| } |
| |
| public String getDefaultServerID() { |
| return defaultServerID; |
| } |
| } |
| |
| /** |
| * parsed ID entry |
| */ |
| public static class IDEntry { |
| private final String type; // provider type (client, server, client-server) |
| private final String moduleClassName; |
| private final MessagePolicy requestPolicy; |
| private final MessagePolicy responsePolicy; |
| private final Map options; |
| |
| public String getModuleClassName() { |
| return moduleClassName; |
| } |
| |
| public Map getOptions() { |
| return options; |
| } |
| |
| public MessagePolicy getRequestPolicy() { |
| return requestPolicy; |
| } |
| |
| public MessagePolicy getResponsePolicy() { |
| return responsePolicy; |
| } |
| |
| public String getType() { |
| return type; |
| } |
| |
| public IDEntry(String type, String moduleClassName, MessagePolicy requestPolicy, MessagePolicy responsePolicy, Map options) { |
| this.type = type; |
| this.moduleClassName = moduleClassName; |
| this.requestPolicy = requestPolicy; |
| this.responsePolicy = responsePolicy; |
| this.options = options; |
| } |
| } |
| |
| /** |
| * A data object contains module object and the corresponding map. |
| */ |
| protected static class ModuleInfo { |
| private final Object module; |
| private final Map map; |
| |
| ModuleInfo(Object module, Map map) { |
| this.module = module; |
| this.map = map; |
| } |
| |
| Object getModule() { |
| return module; |
| } |
| |
| Map getMap() { |
| return map; |
| } |
| } |
| |
| /** |
| * Get an instance of ClientAuthConfig from this provider. |
| * |
| * <p> |
| * The implementation of this method returns a ClientAuthConfig instance that describes the configuration of |
| * ClientAuthModules at a given message layer, and for use in an identified application context. |
| * |
| * @param layer a String identifying the message layer for the returned ClientAuthConfig object. This argument must not |
| * be null. |
| * |
| * @param appContext a String that identifies the messaging context for the returned ClientAuthConfig object. This |
| * argument must not be null. |
| * |
| * @param handler a CallbackHandler to be passed to the ClientAuthModules encapsulated by ClientAuthContext objects |
| * derived from the returned ClientAuthConfig. This argument may be null, in which case the implementation may assign a |
| * default handler to the configuration. |
| * |
| * @return a ClientAuthConfig Object that describes the configuration of ClientAuthModules at the message layer and |
| * messaging context identified by the layer and appContext arguments. This method does not return null. |
| * |
| * @exception AuthException if this provider does not support the assignment of a default CallbackHandler to the |
| * returned ClientAuthConfig. |
| * |
| * @exception SecurityException if the caller does not have permission to retrieve the configuration. |
| * |
| * The CallbackHandler assigned to the configuration must support the Callback objects required to be supported by the |
| * profile of this specification being followed by the messaging runtime. The CallbackHandler instance must be |
| * initialized with any application context needed to process the required callbacks on behalf of the corresponding |
| * application. |
| */ |
| @Override |
| public ClientAuthConfig getClientAuthConfig(String layer, String appContext, CallbackHandler handler) throws AuthException { |
| return new GFClientAuthConfig(this, layer, appContext, handler); |
| } |
| |
| /** |
| * Get an instance of ServerAuthConfig from this provider. |
| * |
| * <p> |
| * The implementation of this method returns a ServerAuthConfig instance that describes the configuration of |
| * ServerAuthModules at a given message layer, and for a particular application context. |
| * |
| * @param layer a String identifying the message layer for the returned ServerAuthConfig object. This argument must not |
| * be null. |
| * |
| * @param appContext a String that identifies the messaging context for the returned ServerAuthConfig object. This |
| * argument must not be null. |
| * |
| * @param handler a CallbackHandler to be passed to the ServerAuthModules encapsulated by ServerAuthContext objects |
| * derived from thr returned ServerAuthConfig. This argument may be null, in which case the implementation may assign a |
| * default handler to the configuration. |
| * |
| * @return a ServerAuthConfig Object that describes the configuration of ServerAuthModules at a given message layer, and |
| * for a particular application context. This method does not return null. |
| * |
| * @exception AuthException if this provider does not support the assignment of a default CallbackHandler to the |
| * returned ServerAuthConfig. |
| * |
| * @exception SecurityException if the caller does not have permission to retrieve the configuration. |
| * <p> |
| * The CallbackHandler assigned to the configuration must support the Callback objects required to be supported by the |
| * profile of this specification being followed by the messaging runtime. The CallbackHandler instance must be |
| * initialized with any application context needed to process the required callbacks on behalf of the corresponding |
| * application. |
| */ |
| @Override |
| public ServerAuthConfig getServerAuthConfig(String layer, String appContext, CallbackHandler handler) throws AuthException { |
| return new GFServerAuthConfig(this, layer, appContext, handler); |
| } |
| |
| /** |
| * Causes a dynamic configuration provider to update its internal state such that any resulting change to its state is |
| * reflected in the corresponding authentication context configuration objects previously created by the provider within |
| * the current process context. |
| * |
| * @exception AuthException if an error occured during the refresh. |
| * |
| * @exception SecurityException if the caller does not have permission to refresh the provider. |
| */ |
| |
| @Override |
| public void refresh() { |
| loadParser(this, factory, null); |
| } |
| |
| /** |
| * this method is intended to be called by the admin configuration system when the corresponding config object has |
| * changed. It relies on the slaves, since it is a static method. |
| * |
| * @param config a config object of type understood by the parser. NOTE: there appears to be a thread saftey problem, |
| * and this method will fail if a slaveProvider has not been established prior to its call. |
| */ |
| public static void loadConfigContext(Object config) { |
| |
| boolean hasSlaveFactory = false; |
| boolean hasSlaveProvider = false; |
| rwLock.readLock().lock(); |
| try { |
| hasSlaveFactory = slaveFactory != null; |
| hasSlaveProvider = slaveProvider != null; |
| } finally { |
| rwLock.readLock().unlock(); |
| } |
| |
| if (slaveProvider == null) { |
| if (logger.isLoggable(Level.SEVERE)) { |
| logger.severe("unableToLoad.noSlaveProvider"); |
| } |
| return; |
| } |
| |
| if (!hasSlaveFactory) { |
| rwLock.writeLock().lock(); |
| try { |
| if (slaveFactory == null) { |
| slaveFactory = AuthConfigFactory.getFactory(); |
| } |
| } finally { |
| rwLock.writeLock().unlock(); |
| } |
| } |
| |
| loadParser(slaveProvider, slaveFactory, config); |
| } |
| |
| protected static void loadParser(AuthConfigProvider aProvider, AuthConfigFactory aFactory, Object config) { |
| rwLock.writeLock().lock(); |
| try { |
| ConfigParser nextParser; |
| int next = epoch + 1; |
| nextParser = (ConfigParser) createObject(parserClassName); |
| nextParser.initialize(config); |
| |
| if (aFactory != null && aProvider != null) { |
| Set<String> layerSet = nextParser.getLayersWithDefault(); |
| for (String layer : layerDefaultRegisIDMap.keySet()) { |
| if (!layerSet.contains(layer)) { |
| String regisID = layerDefaultRegisIDMap.remove(layer); |
| aFactory.removeRegistration(regisID); |
| } |
| } |
| |
| for (String layer : layerSet) { |
| if (!layerDefaultRegisIDMap.containsKey(layer)) { |
| String regisID = aFactory.registerConfigProvider(aProvider, layer, null, |
| "GFServerConfigProvider: self registration"); |
| layerDefaultRegisIDMap.put(layer, regisID); |
| } |
| } |
| } |
| epoch = next == 0 ? 1 : next; |
| parser = nextParser; |
| } catch (IOException ex) { |
| throw new RuntimeException(ex); |
| } finally { |
| rwLock.writeLock().unlock(); |
| } |
| } |
| |
| protected static ClassLoader getClassLoader() { |
| if (System.getSecurityManager() == null) { |
| return Thread.currentThread().getContextClassLoader(); |
| } |
| |
| return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() { |
| @Override |
| public Object run() { |
| return Thread.currentThread().getContextClassLoader(); |
| } |
| }); |
| } |
| |
| // for old API |
| public static void setValidateRequestSubject(Subject subject) { |
| subjectLocal.set(subject); |
| } |
| |
| class GFAuthConfig implements AuthConfig { |
| protected AuthConfigProvider provider = null; |
| protected String layer = null; |
| protected String appContext = null; |
| protected CallbackHandler handler = null; |
| protected String type = null; |
| protected String providerID = null; |
| protected boolean init = false; |
| protected boolean onePolicy = false; |
| // protected boolean newHandler = false; |
| protected MessageSecurityBindingDescriptor binding = null; |
| protected SunWebApp sunWebApp = null; |
| |
| protected GFAuthConfig(AuthConfigProvider provider, String layer, String appContext, CallbackHandler handler, String type) { |
| this.provider = provider; |
| this.layer = layer; |
| this.appContext = appContext; |
| this.type = type; |
| if (handler == null) { |
| handler = AuthMessagePolicy.getDefaultCallbackHandler(); |
| // this.newHandler = true; |
| } |
| this.handler = handler; |
| } |
| |
| /** |
| * Get the message layer name of this authentication context configuration object. |
| * |
| * @return the message layer name of this configuration object, or null if the configuration object pertains to an |
| * unspecified message layer. |
| */ |
| @Override |
| public String getMessageLayer() { |
| return layer; |
| } |
| |
| /** |
| * Get the application context identifier of this authentication context configuration object. |
| * |
| * @return the String identifying the application context of this configuration object or null if the configuration |
| * object pertains to an unspecified application context. |
| */ |
| @Override |
| public String getAppContext() { |
| return appContext; |
| } |
| |
| /** |
| * Get the authentication context identifier corresponding to the request and response objects encapsulated in |
| * messageInfo. |
| * |
| * See method AuthMessagePolicy. getHttpServletPolicies() for more details on why this method returns the String's |
| * "true" or "false" for AuthContextID. |
| * |
| * @param messageInfo a contextual Object that encapsulates the client request and server response objects. |
| * |
| * @return the authentication context identifier corresponding to the encapsulated request and response objects, or |
| * null. |
| * |
| * |
| * @throws IllegalArgumentException if the type of the message objects incorporated in messageInfo are not compatible |
| * with the message types supported by this authentication context configuration object. |
| */ |
| @Override |
| public String getAuthContextID(MessageInfo messageInfo) { |
| if (GFServerConfigProvider.HTTPSERVLET.equals(layer)) { |
| String isMandatoryStr = (String) messageInfo.getMap().get(HttpServletConstants.IS_MANDATORY); |
| return Boolean.valueOf(isMandatoryStr).toString(); |
| } |
| if (GFServerConfigProvider.SOAP.equals(layer)) { |
| if (wsdelegate != null) { |
| return wsdelegate.getAuthContextID(messageInfo); |
| } |
| } |
| return null; |
| } |
| |
| // we should be able to replace the following with a method on packet |
| |
| /** |
| * Causes a dynamic anthentication context configuration object to update the internal state that it uses to process |
| * calls to its <code>getAuthContext</code> method. |
| * |
| * @exception AuthException if an error occured during the update. |
| * |
| * @exception SecurityException if the caller does not have permission to refresh the configuration object. |
| */ |
| @Override |
| public void refresh() { |
| loadParser(provider, factory, null); |
| } |
| |
| /** |
| * Used to determine whether or not the <code>getAuthContext</code> method of the authentication context configuration |
| * will return null for all possible values of authentication context identifier. |
| * |
| * @return false when <code>getAuthContext</code> will return null for all possible values of authentication context |
| * identifier. Otherwise, this method returns true. |
| */ |
| @Override |
| public boolean isProtected() { |
| // XXX TBD |
| return true; |
| } |
| |
| protected AuthParam getAuthParam(MessageInfo info) throws AuthException { |
| |
| if (GFServerConfigProvider.HTTPSERVLET.equals(layer)) { |
| return new HttpServletAuthParam(info); |
| } |
| if (GFServerConfigProvider.SOAP.equals(layer)) { |
| if (wsdelegate != null) { |
| return wsdelegate.newSOAPAuthParam(info); |
| } |
| } |
| throw new AuthException("unsupported AuthParam type"); |
| } |
| |
| CallbackHandler getCallbackHandler() { |
| return handler; |
| } |
| |
| protected ModuleInfo getModuleInfo(String authContextID, Map properties) throws AuthException { |
| if (!init) { |
| initialize(properties); |
| } |
| |
| MessagePolicy[] policies = null; |
| |
| if (GFServerConfigProvider.HTTPSERVLET.equals(layer)) { |
| |
| policies = AuthMessagePolicy.getHttpServletPolicies(authContextID); |
| |
| } else { |
| |
| policies = AuthMessagePolicy.getSOAPPolicies(binding, authContextID, onePolicy); |
| } |
| |
| MessagePolicy requestPolicy = policies[0]; |
| MessagePolicy responsePolicy = policies[1]; |
| |
| Entry entry = getEntry(layer, providerID, requestPolicy, responsePolicy, type); |
| |
| return entry != null ? createModuleInfo(entry, handler, type, properties) : null; |
| } |
| |
| // lazy initialize this as SunWebApp is not available in |
| // RealmAdapter creation |
| private void initialize(Map properties) { |
| if (!init) { |
| |
| if (GFServerConfigProvider.HTTPSERVLET.equals(layer)) { |
| sunWebApp = AuthMessagePolicy.getSunWebApp(properties); |
| providerID = AuthMessagePolicy.getProviderID(sunWebApp); |
| onePolicy = true; |
| } else { |
| binding = AuthMessagePolicy.getMessageSecurityBinding(layer, properties); |
| providerID = AuthMessagePolicy.getProviderID(binding); |
| onePolicy = AuthMessagePolicy.oneSOAPPolicy(binding); |
| } |
| |
| // handlerContext need to be explictly set by caller |
| init = true; |
| } |
| } |
| } |
| |
| class GFServerAuthConfig extends GFAuthConfig implements ServerAuthConfig { |
| |
| protected GFServerAuthConfig(AuthConfigProvider provider, String layer, String appContext, CallbackHandler handler) { |
| super(provider, layer, appContext, handler, SERVER); |
| } |
| |
| @Override |
| public ServerAuthContext getAuthContext(String authContextID, Subject serviceSubject, Map properties) throws AuthException { |
| ServerAuthContext serverAuthContext = null; |
| ModuleInfo moduleInfo = getModuleInfo(authContextID, properties); |
| |
| if (moduleInfo != null && moduleInfo.getModule() != null) { |
| Object moduleObj = moduleInfo.getModule(); |
| Map map = moduleInfo.getMap(); |
| if (moduleObj instanceof ServerAuthModule) { |
| serverAuthContext = new GFServerAuthContext(this, (ServerAuthModule) moduleObj, map); |
| } else { |
| serverAuthContext = new GFServerAuthContext(this, (com.sun.enterprise.security.jauth.ServerAuthModule) moduleObj, map); |
| } |
| } |
| |
| return serverAuthContext; |
| } |
| } |
| |
| class GFClientAuthConfig extends GFAuthConfig implements ClientAuthConfig { |
| |
| protected GFClientAuthConfig(AuthConfigProvider provider, String layer, String appContext, CallbackHandler handler) { |
| super(provider, layer, appContext, handler, CLIENT); |
| } |
| |
| @Override |
| public ClientAuthContext getAuthContext(String authContextID, Subject clientSubject, Map properties) throws AuthException { |
| ClientAuthContext clientAuthContext = null; |
| ModuleInfo moduleInfo = getModuleInfo(authContextID, properties); |
| |
| if (moduleInfo != null && moduleInfo.getModule() != null) { |
| Object moduleObj = moduleInfo.getModule(); |
| Map map = moduleInfo.getMap(); |
| if (moduleObj instanceof ClientAuthModule) { |
| clientAuthContext = new GFClientAuthContext(this, (ClientAuthModule) moduleObj, map); |
| } else { |
| clientAuthContext = new GFClientAuthContext(this, (com.sun.enterprise.security.jauth.ClientAuthModule) moduleObj, map); |
| } |
| } |
| |
| return clientAuthContext; |
| } |
| } |
| |
| static protected class GFServerAuthContext implements ServerAuthContext { |
| |
| private final GFServerAuthConfig config; |
| private final ServerAuthModule module; |
| private final com.sun.enterprise.security.jauth.ServerAuthModule oldModule; |
| |
| private final Map map; |
| boolean managesSession = false; |
| |
| GFServerAuthContext(GFServerAuthConfig config, ServerAuthModule module, Map map) { |
| this.config = config; |
| this.module = module; |
| this.oldModule = null; |
| this.map = map; |
| } |
| |
| GFServerAuthContext(GFServerAuthConfig config, com.sun.enterprise.security.jauth.ServerAuthModule module, Map map) { |
| this.config = config; |
| this.module = null; |
| this.oldModule = module; |
| this.map = map; |
| if (map != null) { |
| String msStr = (String) map.get(GFServerConfigProvider.MANAGES_SESSIONS_OPTION); |
| if (msStr != null) { |
| managesSession = Boolean.valueOf(msStr); |
| } |
| } |
| } |
| |
| // for old modules |
| private static void _setCallerPrincipals(Subject s, CallbackHandler handler, Subject pvcSubject) throws AuthException { |
| |
| if (handler != null) { // handler should be non-null |
| Set<Principal> ps = s.getPrincipals(); |
| if (ps == null || ps.isEmpty()) { |
| return; |
| } |
| Iterator<Principal> it = ps.iterator(); |
| |
| Callback[] callbacks = new Callback[] { new CallerPrincipalCallback(s, it.next().getName()) }; |
| if (pvcSubject != null) { |
| s.getPrincipals().addAll(pvcSubject.getPrincipals()); |
| } |
| |
| try { |
| handler.handle(callbacks); |
| } catch (Exception e) { |
| AuthException aex = new AuthException(); |
| aex.initCause(e); |
| throw aex; |
| } |
| } |
| } |
| |
| // for old modules |
| private static void setCallerPrincipals(final Subject s, final CallbackHandler handler, final Subject pvcSubject) |
| throws AuthException { |
| if (System.getSecurityManager() == null) { |
| _setCallerPrincipals(s, handler, pvcSubject); |
| } else { |
| try { |
| AccessController.doPrivileged(new PrivilegedExceptionAction() { |
| @Override |
| public Object run() throws Exception { |
| _setCallerPrincipals(s, handler, pvcSubject); |
| return null; |
| } |
| }); |
| } catch (PrivilegedActionException pae) { |
| Throwable cause = pae.getCause(); |
| AuthException aex = new AuthException(); |
| aex.initCause(cause); |
| throw aex; |
| } |
| } |
| } |
| |
| @Override |
| public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException { |
| if (module != null) { |
| return module.validateRequest(messageInfo, clientSubject, serviceSubject); |
| } |
| |
| if (oldModule == null) { |
| throw new AuthException(); |
| } |
| try { |
| subjectLocal.remove(); |
| oldModule.validateRequest(config.getAuthParam(messageInfo), clientSubject, messageInfo.getMap()); |
| setCallerPrincipals(clientSubject, config.getCallbackHandler(), subjectLocal.get()); |
| if (!managesSession && GFServerConfigProvider.HTTPSERVLET.equals(config.getMessageLayer())) { |
| messageInfo.getMap().put(HttpServletConstants.REGISTER_WITH_AUTHENTICATOR, Boolean.TRUE.toString()); |
| } |
| return AuthStatus.SUCCESS; |
| } catch (PendingException pe) { |
| return AuthStatus.SEND_CONTINUE; |
| } catch (FailureException fe) { |
| return AuthStatus.SEND_FAILURE; |
| } finally { |
| subjectLocal.remove(); |
| } |
| } |
| |
| @Override |
| public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) throws AuthException { |
| if (module != null) { |
| return module.secureResponse(messageInfo, serviceSubject); |
| } |
| |
| if (oldModule != null) { |
| oldModule.secureResponse(config.getAuthParam(messageInfo), serviceSubject, messageInfo.getMap()); |
| return AuthStatus.SEND_SUCCESS; |
| } |
| throw new AuthException(); |
| } |
| |
| @Override |
| public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException { |
| if (module != null) { |
| module.cleanSubject(messageInfo, subject); |
| } else if (oldModule != null) { |
| oldModule.disposeSubject(subject, messageInfo.getMap()); |
| } else { |
| throw new AuthException(); |
| } |
| } |
| } |
| |
| static protected class GFClientAuthContext implements ClientAuthContext { |
| |
| private final GFClientAuthConfig config; |
| private final ClientAuthModule module; |
| private final com.sun.enterprise.security.jauth.ClientAuthModule oldModule; |
| // private Map map; |
| |
| GFClientAuthContext(GFClientAuthConfig config, ClientAuthModule module, Map map) { |
| this.config = config; |
| this.module = module; |
| this.oldModule = null; |
| // this.map = map; |
| } |
| |
| GFClientAuthContext(GFClientAuthConfig config, com.sun.enterprise.security.jauth.ClientAuthModule module, Map map) { |
| this.config = config; |
| this.module = null; |
| this.oldModule = module; |
| // this.map = map; |
| } |
| |
| @Override |
| public AuthStatus secureRequest(MessageInfo messageInfo, Subject clientSubject) throws AuthException { |
| if (module != null) { |
| return module.secureRequest(messageInfo, clientSubject); |
| } |
| |
| if (oldModule != null) { |
| oldModule.secureRequest(config.getAuthParam(messageInfo), clientSubject, messageInfo.getMap()); |
| return AuthStatus.SEND_SUCCESS; |
| } |
| throw new AuthException(); |
| } |
| |
| @Override |
| public AuthStatus validateResponse(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException { |
| if (module != null) { |
| return module.validateResponse(messageInfo, clientSubject, serviceSubject); |
| } |
| |
| if (oldModule != null) { |
| oldModule.validateResponse(config.getAuthParam(messageInfo), clientSubject, messageInfo.getMap()); |
| return AuthStatus.SUCCESS; |
| } |
| throw new AuthException(); |
| } |
| |
| @Override |
| public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException { |
| if (module != null) { |
| module.cleanSubject(messageInfo, subject); |
| } else if (oldModule != null) { |
| oldModule.disposeSubject(subject, messageInfo.getMap()); |
| } else { |
| throw new AuthException(); |
| } |
| } |
| } |
| } |