blob: ca99577f835257a92653e6ca0acaa980526c8bf6 [file] [log] [blame]
/*
* 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();
}
}
}
}