/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.security.jmac.config;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.Security;
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.servlet.http.HttpServletRequest;
import javax.xml.namespace.QName;
import javax.xml.soap.Name;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.AuthStatus;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.MessagePolicy;
import javax.security.auth.message.callback.CallerPrincipalCallback;
import javax.security.auth.message.config.AuthConfig;
import javax.security.auth.message.config.AuthConfigFactory;
import javax.security.auth.message.config.AuthConfigProvider;
import javax.security.auth.message.config.ClientAuthConfig;
import javax.security.auth.message.config.ClientAuthContext;
import javax.security.auth.message.config.ServerAuthConfig;
import javax.security.auth.message.config.ServerAuthContext;
import javax.security.auth.message.module.ClientAuthModule;
import javax.security.auth.message.module.ServerAuthModule;
import com.sun.enterprise.config.ConfigContext;
import com.sun.enterprise.deployment.WebServiceEndpoint;
import com.sun.enterprise.deployment.runtime.common.MessageDescriptor;
import com.sun.enterprise.deployment.runtime.common.MessageSecurityBindingDescriptor;
import com.sun.enterprise.deployment.runtime.common.MessageSecurityDescriptor;
import com.sun.enterprise.deployment.runtime.web.SunWebApp;
import com.sun.enterprise.deployment.PrincipalImpl;
import com.sun.enterprise.security.AppservAccessController;
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.jauth.SOAPAuthParam;
import com.sun.enterprise.security.jmac.AuthMessagePolicy;
import com.sun.enterprise.security.jmac.PacketMessageInfo;
import com.sun.logging.LogDomains;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.ws.api.model.wsdl.WSDLBoundOperation;
/**
* 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(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.ConfigXMLParser";
// 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<Subject>();
protected static final ReadWriteLock rwLock = new ReentrantReadWriteLock();
protected static final Map<String, String> layerDefaultRegisIDMap = new HashMap<String, String>();
protected static int epoch;
protected static String parserClassName = null;
protected static ConfigParser parser;
protected static boolean parserInitialized = false;
protected static AuthConfigFactory slaveFactory = null;
// keep the slave from visible outside
protected static AuthConfigProvider slaveProvider = null;
protected AuthConfigFactory factory = null;
private GFServerConfigProvider() {
}
public GFServerConfigProvider(Map properties, AuthConfigFactory factory) {
this.factory = factory;
initializeParser();
if (factory != null) {
boolean hasSlaveFactory = false;
rwLock.readLock().lock();
try {
hasSlaveFactory = (slaveFactory != null);
} finally {
rwLock.readLock().unlock();
}
if (!hasSlaveFactory) {
rwLock.writeLock().lock();
try {
if (slaveFactory == null) {
slaveFactory = factory;
}
} finally {
rwLock.writeLock().unlock();
}
}
}
boolean hasSlaveProvider = false;
rwLock.readLock().lock();
try {
hasSlaveProvider = (slaveProvider != null);
} finally {
rwLock.readLock().unlock();
}
if (!hasSlaveProvider) {
rwLock.writeLock().lock();
try {
if (slaveProvider == null) {
slaveProvider = this;
}
} finally {
rwLock.writeLock().unlock();
}
}
}
private void initializeParser() {
rwLock.readLock().lock();
try {
if (parserInitialized) {
return;
}
} finally {
rwLock.readLock().unlock();
}
rwLock.writeLock().lock();
try {
if (!parserInitialized) {
parserClassName =
System.getProperty("config.parser", DEFAULT_PARSER_CLASS);
loadParser(this, factory, null); // null ConfigContext
parserInitialized = true;
}
} finally {
rwLock.writeLock().unlock();
}
}
/**
* Instantiate+initialize module class
*/
protected 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 { // CLIENT
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(String className) {
try {
final String finalClassName = className;
return AppservAccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws Exception {
ClassLoader loader =
Thread.currentThread().getContextClassLoader();
Class c = Class.forName(finalClassName, true, loader);
return c.newInstance();
}
});
} catch (PrivilegedActionException pae) {
throw new RuntimeException(pae.getException());
}
}
protected Entry getEntry(String intercept,
String id, MessagePolicy requestPolicy,
MessagePolicy responsePolicy, String type) {
// get the parsed module config and DD information
Map configMap;
rwLock.readLock().lock();
try {
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 String moduleClassName;
private MessagePolicy requestPolicy;
private MessagePolicy responsePolicy;
private Map options;
Object module; // convenience location to store instance -
// package private for AuthContext
/**
* 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 moduleClass the fully qualified class name of the module.
*
* @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;
}
}
}
static class InterceptEntry {
String defaultClientID;
String defaultServerID;
HashMap idMap;
InterceptEntry(String defaultClientID,
String defaultServerID, HashMap idMap) {
this.defaultClientID = defaultClientID;
this.defaultServerID = defaultServerID;
this.idMap = idMap;
}
}
/**
* parsed ID entry
*/
static class IDEntry {
private String type; // provider type (client, server, client-server)
private String moduleClassName;
private MessagePolicy requestPolicy;
private MessagePolicy responsePolicy;
private Map options;
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 Object module;
private 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.
*/
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 the
* 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.
*/
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.
*/
public void refresh() {
loadParser(this, factory, null); // null ConfigContext
}
public static void loadConfigContext(ConfigContext configContext) {
AuthConfigFactory aFactory = slaveFactory;
if (aFactory == null) {
aFactory = AuthConfigFactory.getFactory();
}
loadParser(slaveProvider, slaveFactory, configContext);
}
protected static void loadParser(AuthConfigProvider aProvider,
AuthConfigFactory aFactory, ConfigContext configContext) {
rwLock.writeLock().lock();
try {
ConfigParser nextParser;
int next = epoch + 1;
nextParser = (ConfigParser)createObject(parserClassName);
nextParser.initialize(configContext);
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() {
final ClassLoader rvalue = (ClassLoader)AppservAccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return Thread.currentThread().getContextClassLoader();
}
});
return rvalue;
}
// 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.
*/
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.
*/
public String getAppContext() {
return appContext;
}
/**
* Get the authentication context identifier corresponding to the
* request and response objects encapsulated in messageInfo.
*
* @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.
*/
public String getAuthContextID(MessageInfo messageInfo) {
//XXX temporary, may need to re-structure the code
if (GFServerConfigProvider.SOAP.equals(layer)) {
// make this more efficient by operating on packet
String rvalue = null;
if (messageInfo instanceof PacketMessageInfo) {
PacketMessageInfo pmi = (PacketMessageInfo) messageInfo;
Packet p = (Packet) pmi.getRequestPacket();
if (p != null) {
Message m = p.getMessage();
if (m != null) {
WSDLPort port =
(WSDLPort) messageInfo.getMap().get("WSDL_MODEL");
if (port != null) {
WSDLBoundOperation w = m.getOperation(port);
if (w != null) {
QName n = w.getName();
if (n != null) {
rvalue = n.getLocalPart();
}
}
}
}
}
return rvalue;
} else {
// make this more efficient by operating on packet
return getOpName((SOAPMessage)messageInfo.getRequestMessage());
}
} else if (GFServerConfigProvider.HTTPSERVLET.equals(layer)) {
String isMandatoryStr =
(String)messageInfo.getMap().get(HttpServletConstants.IS_MANDATORY);
return Boolean.valueOf(isMandatoryStr).toString();
} else {
return null;
}
}
// we should be able to replace the following with a method on packet
private String getOpName(SOAPMessage message) {
if (message == null) {
return null;
}
String rvalue = null;
// first look for a SOAPAction header.
// this is what .net uses to identify the operation
MimeHeaders headers = message.getMimeHeaders();
if (headers != null) {
String[] actions = headers.getHeader("SOAPAction");
if (actions != null && actions.length > 0) {
rvalue = actions[0];
if (rvalue != null && rvalue.equals("\"\"")) {
rvalue = null;
}
}
}
// if that doesn't work then we default to trying the name
// of the first child element of the SOAP envelope.
if (rvalue == null) {
Name name = getName(message);
if (name != null) {
rvalue = name.getLocalName();
}
}
return rvalue;
}
private Name getName(SOAPMessage message) {
Name rvalue = null;
SOAPPart soap = message.getSOAPPart();
if (soap != null) {
try {
SOAPEnvelope envelope = soap.getEnvelope();
if (envelope != null) {
SOAPBody body = envelope.getBody();
if (body != null) {
Iterator it = body.getChildElements();
while (it.hasNext()) {
Object o = it.next();
if (o instanceof SOAPElement) {
rvalue = ((SOAPElement) o).getElementName();
break;
}
}
}
}
} catch (SOAPException se) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "WSS: Unable to get SOAP envelope",
se);
}
}
}
return rvalue;
}
/**
* 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.
*/
public void refresh() {
loadParser(provider, factory, null); // null configContext
}
/**
* 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.
*/
public boolean isProtected() {
// XXX TBD
return true;
}
protected AuthParam getAuthParam(MessageInfo info)
throws AuthException {
if (GFServerConfigProvider.SOAP.equals(layer)) {
if (info instanceof PacketMessageInfo) {
// construct AuthParam with Packets if they are available
return ((PacketMessageInfo)info).getSOAPAuthParam();
} else {
return new SOAPAuthParam((SOAPMessage)
info.getRequestMessage(),
(SOAPMessage)
info.getResponseMessage());
}
} else if (GFServerConfigProvider.HTTPSERVLET.equals(layer)) {
return new HttpServletAuthParam(info);
} else {
throw new AuthException();
}
}
CallbackHandler getCallbackHandler() {
return handler;
}
protected ModuleInfo getModuleInfo(String authContextID, Map properties)
throws AuthException {
if (!init) {
initialize(properties);
}
MessagePolicy[] policies = null;
if (GFServerConfigProvider.SOAP.equals(layer)) {
policies = AuthMessagePolicy.getSOAPPolicies
(binding, authContextID, onePolicy);
} else {
policies = AuthMessagePolicy.getHttpServletPolicies
(authContextID);
}
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.SOAP.equals(layer)) {
binding = AuthMessagePolicy.getMessageSecurityBinding
(layer,properties);
providerID = AuthMessagePolicy.getProviderID(binding);
onePolicy = AuthMessagePolicy.oneSOAPPolicy(binding);
} else {
sunWebApp = AuthMessagePolicy.getSunWebApp(properties);
providerID = AuthMessagePolicy.getProviderID(sunWebApp);
onePolicy = true;
}
// 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);
}
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);
}
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 GFServerAuthConfig config;
private ServerAuthModule module;
private com.sun.enterprise.security.jauth.ServerAuthModule oldModule;
private Map map;
boolean managesSession = false;
protected GFServerAuthContext(GFServerAuthConfig config,
ServerAuthModule module, Map map) {
this.config = config;
this.module = module;
this.oldModule = null;
this.map = map;
}
protected 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(final Subject s,
final CallbackHandler handler, final Subject pvcSubject)
throws AuthException {
if (handler != null) { // handler should be non-null
try {
AppservAccessController.doPrivileged
(new PrivilegedExceptionAction() {
public Object run() throws Exception {
Set<Principal> ps = s.getPrincipals();
Iterator<Principal> it = ps.iterator();
if (ps == null || ps.isEmpty()) {
return null ;
}
Callback[] callbacks = new Callback[] {
new CallerPrincipalCallback(
s, it.next().getName()) };
if (pvcSubject != null) {
s.getPrincipals().addAll(
pvcSubject.getPrincipals());
}
handler.handle(callbacks);
return null;
}
});
} catch(PrivilegedActionException pae) {
Throwable cause = pae.getCause();
AuthException aex = new AuthException();
aex.initCause(cause);
throw aex;
}
}
}
public AuthStatus validateRequest(MessageInfo messageInfo,
Subject clientSubject, Subject serviceSubject)
throws AuthException {
if (module != null) {
return module.validateRequest
(messageInfo, clientSubject, serviceSubject);
} else if (oldModule != null) {
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();
}
} else {
throw new AuthException();
}
}
public AuthStatus secureResponse(MessageInfo messageInfo,
Subject serviceSubject) throws AuthException {
if (module != null) {
return module.secureResponse(messageInfo, serviceSubject);
} else if (oldModule != null) {
oldModule.secureResponse(config.getAuthParam(messageInfo),
serviceSubject,
messageInfo.getMap());
return AuthStatus.SEND_SUCCESS;
} else {
throw new AuthException();
}
}
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 GFClientAuthConfig config;
private ClientAuthModule module;
private com.sun.enterprise.security.jauth.ClientAuthModule oldModule;
private Map map;
protected GFClientAuthContext(GFClientAuthConfig config,
ClientAuthModule module, Map map) {
this.config = config;
this.module = module;
this.oldModule = null;
this.map = map;
}
protected GFClientAuthContext(GFClientAuthConfig config,
com.sun.enterprise.security.jauth.ClientAuthModule module,
Map map) {
this.config = config;
this.module = null;
this.oldModule = module;
this.map = map;
}
public AuthStatus secureRequest(MessageInfo messageInfo,
Subject clientSubject) throws AuthException {
if (module != null) {
return module.secureRequest(messageInfo, clientSubject);
} else if (oldModule != null) {
oldModule.secureRequest(config.getAuthParam(messageInfo),
clientSubject,
messageInfo.getMap());
return AuthStatus.SEND_SUCCESS;
} else {
throw new AuthException();
}
}
public AuthStatus validateResponse(MessageInfo messageInfo,
Subject clientSubject, Subject serviceSubject)
throws AuthException {
if (module != null) {
return module.validateResponse(messageInfo, clientSubject,
serviceSubject);
} else if (oldModule != null) {
oldModule.validateResponse(config.getAuthParam(messageInfo),
clientSubject, messageInfo.getMap());
return AuthStatus.SUCCESS;
} else {
throw new AuthException();
}
}
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();
}
}
}
}