com.sun.enterprise.security.jauth.ConfigFile Maven / Gradle / Ivy
Show all versions of payara-micro Show documentation
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2011 Oracle and/or its affiliates. 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_1_1.html
* or packager/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 packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [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.jauth;
import com.sun.enterprise.security.jmac.config.ConfigParser;
import com.sun.enterprise.security.jmac.config.GFServerConfigProvider;
import java.io.*;
import java.util.*;
import java.lang.reflect.Method;
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 javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.AppConfigurationEntry;
import com.sun.logging.LogDomains;
/**
* This is a default file-based AuthConfig implementation.
*
* @version %I%, %G%
*/
class ConfigFile extends AuthConfig {
// indicates the age of the configuration approximately in
// terms of the number of times refresh has been called
private int epoch;
// parser class name
private String parserClassName;
// parser
private ConfigParser parser;
// package private for ConfigFileParser
static final String CLIENT = "client";
static final String SERVER = "server";
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";
private static final Logger logger = LogDomains.getLogger(ConfigFile.class, LogDomains.SECURITY_LOGGER);
ConfigFile() throws IOException {
String propertyValue = System.getProperty("config.parser");
if (propertyValue == null) {
parserClassName = DEFAULT_PARSER_CLASS;
} else {
parserClassName = propertyValue;
}
this.epoch = 1;
parser = ConfigFile.loadParser(parserClassName);
parser.initialize(null);
}
/**
* Get a default ClientAuthContext.
*
* @return an instance of ConfigClient.
*/
public ClientAuthContext getClientAuthContext(String intercept,
String id,
AuthPolicy requestPolicy,
AuthPolicy responsePolicy,
CallbackHandler handler)
throws AuthException {
ConfigFile.Entry[] entries = getEntries(intercept,
id,
requestPolicy,
responsePolicy,
CLIENT);
if (entries == null || entries.length == 0) {
return null;
}
// instantiate and initialize modules up front as well
if (handler == null) {
handler = ConfigFile.loadDefaultCallbackHandler();
} else if (handler instanceof DependentCallbackHandler) {
handler = new DelegatingHandler(handler);
}
for (int i = 0; i < entries.length; i++) {
entries[i].module = ConfigFile.createModule(entries[i], handler);
}
return new ConfigClient(entries);
}
/**
* Get a default ServerAuthContext.
*
* @return an instance of ConfigServer.
*/
public ServerAuthContext getServerAuthContext(String intercept,
String id,
AuthPolicy requestPolicy,
AuthPolicy responsePolicy,
CallbackHandler handler)
throws AuthException {
ConfigFile.Entry[] entries = getEntries(intercept,
id,
requestPolicy,
responsePolicy,
SERVER);
if (entries == null || entries.length == 0) {
return null;
}
// instantiate and initialize modules up front as well
if (handler == null) {
handler = ConfigFile.loadDefaultCallbackHandler();
} else if (handler instanceof DependentCallbackHandler) {
handler = new DelegatingHandler(handler);
}
for (int i = 0; i < entries.length; i++) {
entries[i].module = ConfigFile.createModule(entries[i], handler);
}
return new ConfigServer(entries);
}
public void refresh() throws AuthException {
synchronized (this) {
ConfigParser nextParser;
int next = this.epoch + 1;
try {
nextParser = ConfigFile.loadParser(parserClassName);
} catch (IOException ioe) {
throw new AuthException(ioe.toString());
}
this.epoch = (next == 0 ? 1 : next);
parser = nextParser;
}
}
private ConfigFile.Entry[] getEntries(String intercept,
String id,
AuthPolicy requestPolicy,
AuthPolicy responsePolicy,
String type) {
// get the parsed module config and DD information
Map configMap;
synchronized (parser) {
configMap = parser.getConfigMap();
}
if (configMap == null) {
return null;
}
// get the module config info for this intercept
GFServerConfigProvider.InterceptEntry intEntry = (GFServerConfigProvider.InterceptEntry)configMap.get(intercept);
if (intEntry == null || intEntry.getIdMap() == null) {
if (logger != null && 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
GFServerConfigProvider.IDEntry idEntry = null;
if (id == null || (idEntry = (GFServerConfigProvider.IDEntry)intEntry.getIdMap().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 != null && 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.getDefaultClientID();
} else {
defaultID = intEntry.getDefaultServerID();
}
idEntry = (GFServerConfigProvider.IDEntry)intEntry.getIdMap().get(defaultID);
if (idEntry == null) {
// did not find a default provider ID
if (logger != null && 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.getType().indexOf(type) < 0) {
if (logger != null && logger.isLoggable(Level.FINE)) {
logger.fine("request type [" +
type +
"] does not match config type [" +
idEntry.getType() +
"]");
}
return null;
}
// check whether a policy is set
AuthPolicy reqP, respP;
if(requestPolicy != null || responsePolicy != null) {
reqP = requestPolicy;
respP = responsePolicy;
} else if(idEntry.getRequestPolicy() != null || idEntry.getResponsePolicy() != null) {
//default
reqP = new AuthPolicy(idEntry.getRequestPolicy());
respP = new AuthPolicy(idEntry.getResponsePolicy());
} else {
// optimization: if policy was not set, return null
if (logger != null && logger.isLoggable(Level.FINE)) {
logger.fine("no policy applies");
}
return null;
}
// return the configured modules with the correct policies
// ConfigFile.Entry[] entries = new Entry[idEntry.modules.size()];
ConfigFile.Entry[] entries = new Entry[1];
for (int i = 0; i < entries.length; i++) {
// Login Bridge profile?
// AppConfigurationEntry aEntry =
// (AppConfigurationEntry)idEntry.modules.get(i);
entries[i] = new ConfigFile.Entry(reqP,
respP,
idEntry.getModuleClassName(),
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
idEntry.getOptions());
}
if (logger != null && logger.isLoggable(Level.FINE)) {
logger.fine("getEntries found " +
entries.length +
" entries for: " +
intercept +
" -- "
+ id);
for (int i = 0; i < entries.length; i++) {
logger.fine("Entry " + (i+1) + ":" +
"\n module class: " + entries[i].getLoginModuleName() +
"\n flag: " + entries[i].getControlFlag() +
"\n options: " + entries[i].getOptions() +
"\n request policy: " + entries[i].requestPolicy +
"\n response policy: " + entries[i].responsePolicy);
}
}
return entries;
}
/**
* get a custom config file parser
*
* XXX custom file that can be used in place of [domain|sun-acc].xml
*/
private static ConfigParser loadParser(String className)
throws IOException {
try {
final String finalClassName = className;
final ClassLoader finalLoader = AuthConfig.getClassLoader();
return (ConfigParser)java.security.AccessController.doPrivileged
(new java.security.PrivilegedExceptionAction() {
public Object run() throws Exception {
Class c = Class.forName(finalClassName,true,finalLoader);
return c.newInstance();
}
});
} catch (java.security.PrivilegedActionException pae) {
IOException iex = new IOException(pae.getException().toString());
iex.initCause(pae.getException());
throw iex;
}
}
/**
* get the default callback handler
*/
private static CallbackHandler loadDefaultCallbackHandler()
throws AuthException {
// get the default handler class
try {
final ClassLoader finalLoader = AuthConfig.getClassLoader();
return (CallbackHandler)
java.security.AccessController.doPrivileged
(new java.security.PrivilegedExceptionAction() {
public Object run() throws Exception {
String className = DEFAULT_HANDLER_CLASS;
Class c = Class.forName(className,
true,
finalLoader);
return c.newInstance();
}
});
} catch (java.security.PrivilegedActionException pae) {
AuthException aex = new AuthException(pae.getException().toString());
aex.initCause(pae.getException());
throw aex;
}
}
/**
* Instantiate+initialize module class
*/
private static Object createModule(ConfigFile.Entry entry,
CallbackHandler handler)
throws AuthException {
try {
// instantiate module using no-arg constructor
Object newModule = entry.newInstance();
// initialize module
Object[] initArgs = { entry.getRequestPolicy(),
entry.getResponsePolicy(),
handler,
entry.getOptions() };
try {
Method initMethod = newModule.getClass().getMethod(AuthContext.INIT,
AuthPolicy.class, AuthPolicy.class, CallbackHandler.class,
Map.class);
initMethod.invoke(newModule, initArgs);
// return the new module
return newModule;
} catch(Exception ex) {
throw new SecurityException("could not invoke " +
AuthContext.INIT +
" method in module: " +
newModule.getClass().getName() + " " + ex, ex);
}
} catch (Exception e) {
if (e instanceof AuthException) {
throw (AuthException)e;
}
AuthException ae = new AuthException();
ae.initCause(e);
throw ae;
}
}
/**
* Class representing a single AuthModule entry configured
* for an ID, interception point, and stack.
*
* An instance of this class contains the same
* information as its superclass, AppConfigurationEntry.
* It additionally stores the request and response policy assigned
* to this module.
*
*
This class also provides a way for a caller to obtain
* an instance of the module listed in the entry by invoking
* the newInstance
method.
*/
static class Entry extends javax.security.auth.login.AppConfigurationEntry {
// for loading modules
private static final Class[] PARAMS = { };
private static final Object[] ARGS = { };
private AuthPolicy requestPolicy;
private AuthPolicy responsePolicy;
Object module = null; // convenience location to store instance -
// package private for AuthContext
/**
* Construct a ConfigFile entry.
*
*
An entry encapsulates a single module and its related
* information.
*
* @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 flag the module control flag. This value must either
* be REQUIRED, REQUISITE, SUFFICIENT, or OPTIONAL.
*
* @param options the options configured for this module.
*/
Entry(AuthPolicy requestPolicy,
AuthPolicy responsePolicy,
String moduleClass,
AppConfigurationEntry.LoginModuleControlFlag flag,
Map options) {
super(moduleClass, flag, options);
this.requestPolicy = requestPolicy;
this.responsePolicy = responsePolicy;
}
/**
* Return the request policy assigned to this module.
*
* @return the policy, which may be null.
*/
AuthPolicy getRequestPolicy() {
return requestPolicy;
}
/**
* Return the response policy assigned to this module.
*
* @return the policy, which may be null.
*/
AuthPolicy getResponsePolicy() {
return responsePolicy;
}
/**
* Return a new instance of the module contained in this entry.
*
*
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= AuthConfig.getClassLoader();
String clazz = getLoginModuleName();
Class c = Class.forName(clazz,
true,
finalLoader);
java.lang.reflect.Constructor constructor =
c.getConstructor(PARAMS);
return constructor.newInstance(ARGS);
} catch (Exception e) {
AuthException ae = new AuthException();
ae.initCause(e);
throw ae;
}
}
}
/**
* parsed Intercept entry
*/
/* 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 AuthPolicy requestPolicy;
private AuthPolicy responsePolicy;
private ArrayList modules;
IDEntry(String type,
AuthPolicy requestPolicy,
AuthPolicy responsePolicy,
ArrayList modules) {
this.type = type;
this.modules = modules;
this.requestPolicy = requestPolicy;
this.responsePolicy = responsePolicy;
}
// XXX delete this later
IDEntry(String type,
String requestPolicy,
String responsePolicy,
ArrayList modules) {
this.type = type;
if (requestPolicy != null) {
this.requestPolicy =
new AuthPolicy(AuthPolicy.SOURCE_AUTH_SENDER,
true, // recipient-auth
true); // beforeContent
}
if (responsePolicy != null) {
this.responsePolicy =
new AuthPolicy(AuthPolicy.SOURCE_AUTH_CONTENT,
true, // recipient-auth
false); // beforeContent
}
this.modules = modules;
}
} */
/**
* Default implementation of ClientAuthContext.
*/
private static class ConfigClient implements ClientAuthContext {
// class that does all the work
private AuthContext context;
ConfigClient(Entry[] entries) throws AuthException {
context = new AuthContext(entries, logger);
}
public void secureRequest(AuthParam param,
Subject subject,
Map sharedState)
throws AuthException {
// invoke modules
Object[] args = { param, subject, sharedState };
context.invoke(AuthContext.SECURE_REQUEST, args);
}
public void validateResponse(AuthParam param,
Subject subject,
Map sharedState)
throws AuthException {
// invoke modules
Object[] args = { param, subject, sharedState };
context.invoke(AuthContext.VALIDATE_RESPONSE, args);
}
public void disposeSubject(Subject subject,
Map sharedState)
throws AuthException {
// invoke modules
Object[] args = { subject, sharedState };
context.invoke(AuthContext.DISPOSE_SUBJECT, args);
}
}
/**
* Default implementation of ServerAuthContext.
*/
private static class ConfigServer implements ServerAuthContext {
// class that does all the work
private AuthContext context;
ConfigServer(Entry[] entries) throws AuthException {
context = new AuthContext(entries, logger);
}
public void validateRequest(AuthParam param,
Subject subject,
Map sharedState)
throws AuthException {
// invoke modules
Object[] args = { param, subject, sharedState };
context.invoke(AuthContext.VALIDATE_REQUEST, args);
}
public void secureResponse(AuthParam param,
Subject subject,
Map sharedState)
throws AuthException {
// invoke modules
Object[] args = { param, subject, sharedState };
context.invoke(AuthContext.SECURE_RESPONSE, args);
}
public void disposeSubject(Subject subject,
Map sharedState)
throws AuthException {
// invoke modules
Object[] args = { subject, sharedState };
context.invoke(AuthContext.DISPOSE_SUBJECT, args);
}
public boolean managesSessions(Map sharedState)
throws AuthException {
// invoke modules
Object[] args = { sharedState };
Object[] rValues = null;
try {
rValues = context.invoke(AuthContext.MANAGES_SESSIONS, args);
} catch (AuthException ae) {
// this new method may not be implemeneted
// by old modules
if (!(ae.getCause() instanceof NoSuchMethodException)) {
throw ae;
}
}
boolean rvalue = false;
for (int i=0; rValues != null && i