/* * @(#)LoginContext.java 1.98 04/06/28 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.security.auth.login; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.util.LinkedList; import java.util.Map; import java.util.HashMap; import java.text.MessageFormat; import javax.security.auth.Subject; import javax.security.auth.AuthPermission; import javax.security.auth.callback.*; import java.security.AccessController; import java.security.AccessControlContext; import sun.security.util.PendingException; import sun.security.util.ResourcesMgr; /** *
 The LoginContext class describes the basic methods used
 * to authenticate Subjects and provides a way to develop an
 * application independent of the underlying authentication technology.
 * A Configuration specifies the authentication technology, or
 * LoginModule, to be used with a particular application.
 * Different LoginModules can be plugged in under an application
 * without requiring any modifications to the application itself.
 *
 * 
In addition to supporting pluggable authentication, this class * also supports the notion of stacked authentication. * Applications may be configured to use more than one * LoginModule. For example, one could * configure both a Kerberos LoginModule and a smart card * LoginModule under an application. * *
 A typical caller instantiates a LoginContext with
 * a name and a CallbackHandler.
 * LoginContext uses the name as the index into a
 * Configuration to determine which LoginModules should be used,
 * and which ones must succeed in order for the overall authentication to
 * succeed.  The CallbackHandler is passed to the underlying
 * LoginModules so they may communicate and interact with users
 * (prompting for a username and password via a graphical user interface,
 * for example).
 *
 * 
 Once the caller has instantiated a LoginContext,
 * it invokes the login method to authenticate
 * a Subject.  The login method invokes
 * the configured modules to perform their respective types of authentication
 * (username/password, smart card pin verification, etc.).
 * Note that the LoginModules will not attempt authentication retries nor
 * introduce delays if the authentication fails.
 * Such tasks belong to the LoginContext caller.
 *
 * 
 If the login method returns without
 * throwing an exception, then the overall authentication succeeded.
 * The caller can then retrieve
 * the newly authenticated Subject by invoking the
 * getSubject method.  Principals and Credentials associated
 * with the Subject may be retrieved by invoking the Subject's
 * respective getPrincipals, getPublicCredentials,
 * and getPrivateCredentials methods.
 *
 * 
 To logout the Subject, the caller calls
 * the logout method.  As with the login
 * method, this logout method invokes the logout
 * method for the configured modules.
 * 
 * 
A LoginContext should not be used to authenticate * more than one Subject. A separate LoginContext * should be used to authenticate each different Subject. * *
The following documentation applies to all LoginContext constructors: *
Subject
 * *
null Subject
 * and a null value is permitted,
 * the LoginContext instantiates a new Subject.
 * *
*
Configuration 
 * 
 * If the constructor does not have a Configuration
 * input parameter, or if the caller specifies a null
 * Configuration object, the constructor uses the following call to
 * get the installed Configuration:
 * 
* config = Configuration.getConfiguration(); ** For both cases, * the name argument given to the constructor is passed to the *
Configuration.getAppConfigurationEntry method.
 * If the Configuration has no entries for the specified name,
 * then the LoginContext calls
 * getAppConfigurationEntry with the name, "other"
 * (the default entry name).  If there is no entry for "other",
 * then a LoginException is thrown.
 * *
AccessController.doPrivileged call so that modules that
 * perform security-sensitive tasks (such as connecting to remote hosts,
 * and updating the Subject) will require the respective permissions, but
 * the callers of the LoginContext will not require those permissions.
 * *
AccessControlContext for the caller,
 * and invokes the configured modules from within an
 * AccessController.doPrivileged call constrained by that context.
 * This means the caller context (stored when the LoginContext was created)
 * must have sufficient permissions to perform any security-sensitive tasks
 * that the modules may perform.
 * *
CallbackHandler
 * *
null
 * CallbackHandler object (and a null value is permitted),
 * the LoginContext queries the
 * auth.login.defaultCallbackHandler security property
 * for the fully qualified class name of a default handler implementation.
 * If the security property is not set,
 * then the underlying modules will not have a
 * CallbackHandler for use in communicating
 * with users.  The caller thus assumes that the configured
 * modules have alternative means for authenticating the user.
 *
 * *
handle method implementation invokes the
 * specified CallbackHandler's handle method in a
 * java.security.AccessController.doPrivileged call
 * constrained by the caller's current AccessControlContext.
 *  Note that Security Properties
 * (such as auth.login.defaultCallbackHandler)
 * can be set programmatically via the
 * java.security.Security class,
 * or statically in the Java security properties file located in the
 * file named <JAVA_HOME>/lib/security/java.security,
 * where <JAVA_HOME> refers to the directory where the JDK
 * was installed.
 * 
 * @version 1.98, 06/28/04
 * @see java.security.Security
 * @see javax.security.auth.AuthPermission
 * @see javax.security.auth.Subject
 * @see javax.security.auth.callback.CallbackHandler
 * @see javax.security.auth.login.Configuration
 * @see javax.security.auth.spi.LoginModule
 */
public class LoginContext {
    private static final String INIT_METHOD		= "initialize";
    private static final String LOGIN_METHOD		= "login";
    private static final String COMMIT_METHOD		= "commit";
    private static final String ABORT_METHOD		= "abort";
    private static final String LOGOUT_METHOD		= "logout";
    private static final String OTHER			= "other";
    private static final String DEFAULT_HANDLER		=
				"auth.login.defaultCallbackHandler";
    private Subject subject = null;
    private boolean subjectProvided = false;
    private boolean loginSucceeded = false;
    private CallbackHandler callbackHandler;
    private Map state = new HashMap();
    private Configuration config;
    private boolean configProvided = false;
    private AccessControlContext creatorAcc = null;
    private ModuleInfo[] moduleStack;
    private ClassLoader contextClassLoader = null;
    private static final Class[] PARAMS = { };
    // state saved in the event a user-specified asynchronous exception
    // was specified and thrown
    private int moduleIndex = 0;
    private LoginException firstError = null;
    private LoginException firstRequiredError = null;
    private boolean success = false;
    private static final sun.security.util.Debug debug =
	sun.security.util.Debug.getInstance("logincontext", "\t[LoginContext]");
    private void init(String name) throws LoginException {
	SecurityManager sm = System.getSecurityManager();
	if (sm != null && !configProvided) {
	    sm.checkPermission(new AuthPermission
				("createLoginContext." + name));
	}
	if (name == null)
	    throw new LoginException
		(ResourcesMgr.getString("Invalid null input: name"));
	// get the Configuration
	if (config == null) {
	    config = (Configuration)java.security.AccessController.doPrivileged
		(new java.security.PrivilegedAction() {
		public Object run() {	
		    return Configuration.getConfiguration();
		}
	    });
	}
	// get the LoginModules configured for this application
	AppConfigurationEntry[] entries = config.getAppConfigurationEntry(name);
	if (entries == null) {
	    if (sm != null && !configProvided) {
		sm.checkPermission(new AuthPermission
				("createLoginContext." + OTHER));
	    }
	    entries = config.getAppConfigurationEntry(OTHER);
	    if (entries == null) {
		MessageFormat form = new MessageFormat(ResourcesMgr.getString
			("No LoginModules configured for name"));
		Object[] source = {name};
		throw new LoginException(form.format(source));
	    }
	}
	moduleStack = new ModuleInfo[entries.length];
	for (int i = 0; i < entries.length; i++) {
	    // clone returned array
	    moduleStack[i] = new ModuleInfo
				(new AppConfigurationEntry
					(entries[i].getLoginModuleName(),
					entries[i].getControlFlag(),
					entries[i].getOptions()),
				null);
	}
	contextClassLoader =
		(ClassLoader)java.security.AccessController.doPrivileged
		(new java.security.PrivilegedAction() {
		public Object run() {	
		    return Thread.currentThread().getContextClassLoader();
		}
	});
    }
    private void loadDefaultCallbackHandler() throws LoginException {
	// get the default handler class
	try {
	    final ClassLoader finalLoader = contextClassLoader;
	    this.callbackHandler = (CallbackHandler)
		java.security.AccessController.doPrivileged
		(new java.security.PrivilegedExceptionAction() {
		public Object run() throws Exception {
		    String defaultHandler = java.security.Security.getProperty
			(DEFAULT_HANDLER);
		    if (defaultHandler == null || defaultHandler.length() == 0)
			return null;
		    Class c = Class.forName(defaultHandler,
					true,
					finalLoader);
		    return c.newInstance();
		}
	    });
	} catch (java.security.PrivilegedActionException pae) {
	    throw new LoginException(pae.getException().toString());
	}
	// secure it with the caller's ACC
	if (this.callbackHandler != null && !configProvided) {
	    this.callbackHandler = new SecureCallbackHandler
				(java.security.AccessController.getContext(),
				this.callbackHandler);
	}
    }
    /**
     * Instantiate a new LoginContext object with a name.
     *
     * @param name the name used as the index into the
     *		Configuration.
     *
     * @exception LoginException if the caller-specified name
     *		does not appear in the Configuration
     *		and there is no Configuration entry
     *		for "other", or if the
     *		auth.login.defaultCallbackHandler
     *		security property was set, but the implementation
     *		class could not be loaded.
     *		
     * @exception SecurityException if a SecurityManager is set and
     *		the caller does not have
     *		AuthPermission("createLoginContext.name"),
     *		or if a configuration entry for name does not exist and
     *		the caller does not additionally have
     *		AuthPermission("createLoginContext.other")
     */
    public LoginContext(String name) throws LoginException {
	init(name);
	loadDefaultCallbackHandler();
    }
    /**
     * Instantiate a new LoginContext object with a name
     * and a Subject object.
     *
     * 
     *
     * @param name the name used as the index into the
     *		Configuration. 
     *
     * @param subject the Subject to authenticate.
     *
     * @exception LoginException if the caller-specified name
     *		does not appear in the Configuration
     *          and there is no Configuration entry
     *          for "other", if the caller-specified subject
     *		is null, or if the
     *		auth.login.defaultCallbackHandler
     *		security property was set, but the implementation
     *		class could not be loaded.
     *		
     * @exception SecurityException if a SecurityManager is set and
     *		the caller does not have
     *		AuthPermission("createLoginContext.name"),
     *		or if a configuration entry for name does not exist and
     *		the caller does not additionally have
     *		AuthPermission("createLoginContext.other")
     */
    public LoginContext(String name, Subject subject)
    throws LoginException {
	init(name);
	if (subject == null)
	    throw new LoginException
		(ResourcesMgr.getString("invalid null Subject provided"));
	this.subject = subject;
	subjectProvided = true;
	loadDefaultCallbackHandler();
    }
    /**
     * Instantiate a new LoginContext object with a name
     * and a CallbackHandler object.
     *
     * 
     *
     * @param name the name used as the index into the
     *		Configuration. 
     *
     * @param callbackHandler the CallbackHandler object used by
     *		LoginModules to communicate with the user.
     *
     * @exception LoginException if the caller-specified name
     *          does not appear in the Configuration
     *          and there is no Configuration entry
     *          for "other", or if the caller-specified
     *		callbackHandler is null.
     *		
     * @exception SecurityException if a SecurityManager is set and
     *		the caller does not have
     *		AuthPermission("createLoginContext.name"),
     *		or if a configuration entry for name does not exist and
     *		the caller does not additionally have
     *		AuthPermission("createLoginContext.other")
     */
    public LoginContext(String name, CallbackHandler callbackHandler)
    throws LoginException {
	init(name);
	if (callbackHandler == null)
	    throw new LoginException(ResourcesMgr.getString
				("invalid null CallbackHandler provided"));
	this.callbackHandler = new SecureCallbackHandler
				(java.security.AccessController.getContext(),
				callbackHandler);
    }
    /**
     * Instantiate a new LoginContext object with a name,
     * a Subject to be authenticated, and a
     * CallbackHandler object.
     *
     * 
     *
     * @param name the name used as the index into the
     *		Configuration. 
     *
     * @param subject the Subject to authenticate. 
     *
     * @param callbackHandler the CallbackHandler object used by
     *		LoginModules to communicate with the user.
     *
     * @exception LoginException if the caller-specified name
     *          does not appear in the Configuration
     *          and there is no Configuration entry
     *          for "other", or if the caller-specified
     *		subject is null,
     *		or if the caller-specified
     *		callbackHandler is null.
     *		
     * @exception SecurityException if a SecurityManager is set and
     *		the caller does not have
     *		AuthPermission("createLoginContext.name"),
     *		or if a configuration entry for name does not exist and
     *		the caller does not additionally have
     *		AuthPermission("createLoginContext.other")
     */
    public LoginContext(String name, Subject subject,
			CallbackHandler callbackHandler) throws LoginException {
	this(name, subject);
	if (callbackHandler == null)
	    throw new LoginException(ResourcesMgr.getString
				("invalid null CallbackHandler provided"));
	this.callbackHandler = new SecureCallbackHandler
				(java.security.AccessController.getContext(),
				callbackHandler);
    }
    /**
     * Instantiate a new LoginContext object with a name,
     * a Subject to be authenticated,
     * a CallbackHandler object, and a login
     * Configuration.
     *
     * 
     *
     * @param name the name used as the index into the caller-specified
     *          Configuration. 
     *
     * @param subject the Subject to authenticate,
     *          or null. 
     *
     * @param callbackHandler the CallbackHandler object used by
     *          LoginModules to communicate with the user, or null.
     *		
     *
     * @param config the Configuration that lists the
     *          login modules to be called to perform the authentication,
     *          or null.
     *
     * @exception LoginException if the caller-specified name
     *          does not appear in the Configuration
     *          and there is no Configuration entry
     *          for "other".
     *		
     * @exception SecurityException if a SecurityManager is set,
     *		config is null,
     *		and either the caller does not have
     *		AuthPermission("createLoginContext.name"),
     *		or if a configuration entry for name does not exist and
     *		the caller does not additionally have
     *		AuthPermission("createLoginContext.other")
     *
     * @since 1.5
     */
    public LoginContext(String name, Subject subject,
                        CallbackHandler callbackHandler,
                        Configuration config) throws LoginException {
	this.config = config;
	configProvided = (config != null) ? true : false;
	if (configProvided) {
	    creatorAcc = java.security.AccessController.getContext();
	}
	
	init(name);
	if (subject != null) {
	    this.subject = subject;
	    subjectProvided = true;
	}
	if (callbackHandler == null) {
	    loadDefaultCallbackHandler();
	} else if (!configProvided) {
	    this.callbackHandler = new SecureCallbackHandler
				(java.security.AccessController.getContext(),
				callbackHandler);
	} else {
	    this.callbackHandler = callbackHandler;
	}
    }
    /**
     * Perform the authentication.
     *
     * 
 This method invokes the login method for each
     * LoginModule configured for the name specified to the
     * LoginContext constructor, as determined by the login
     * Configuration.  Each LoginModule
     * then performs its respective type of authentication
     * (username/password, smart card pin verification, etc.).
     *
     * 
 This method completes a 2-phase authentication process by
     * calling each configured LoginModule's commit method
     * if the overall authentication succeeded (the relevant REQUIRED,
     * REQUISITE, SUFFICIENT, and OPTIONAL LoginModules succeeded),
     * or by calling each configured LoginModule's abort method
     * if the overall authentication failed.  If authentication succeeded,
     * each successful LoginModule's commit method associates
     * the relevant Principals and Credentials with the Subject.
     * If authentication failed, each LoginModule's abort method
     * removes/destroys any previously stored state.
     *
     * 
 If the commit phase of the authentication process
     * fails, then the overall authentication fails and this method
     * invokes the abort method for each configured
     * LoginModule.
     *
     * 
 If the abort phase
     * fails for any reason, then this method propagates the
     * original exception thrown either during the login phase
     * or the commit phase.  In either case, the overall
     * authentication fails.
     *
     * 
 In the case where multiple LoginModules fail,
     * this method propagates the exception raised by the first
     * LoginModule which failed.
     *
     * 
 Note that if this method enters the abort phase
     * (either the login or commit phase failed),
     * this method invokes all LoginModules configured for the
     * application regardless of their respective Configuration
     * flag parameters.  Essentially this means that Requisite
     * and Sufficient semantics are ignored during the
     * abort phase.  This guarantees that proper cleanup
     * and state restoration can take place.
     * 
     * 
     *
     * @exception LoginException if the authentication fails.
     */
    public void login() throws LoginException {
	loginSucceeded = false;
	if (subject == null) {
	    subject = new Subject();
	}
	try {
	    if (configProvided) {
		// module invoked in doPrivileged with creatorAcc
		invokeCreatorPriv(LOGIN_METHOD);
		invokeCreatorPriv(COMMIT_METHOD);
	    } else {
		// module invoked in doPrivileged
		invokePriv(LOGIN_METHOD);
		invokePriv(COMMIT_METHOD);
	    }
	    loginSucceeded = true;
	} catch (LoginException le) {
	    try {
		if (configProvided) {
		    invokeCreatorPriv(ABORT_METHOD);
		} else {
		    invokePriv(ABORT_METHOD);
		}
	    } catch (LoginException le2) {
		throw le;
	    }
	    throw le;
	}
    }
    /**
     * Logout the Subject.
     *
     * 
 This method invokes the logout method for each
     * LoginModule configured for this LoginContext.
     * Each LoginModule performs its respective logout procedure
     * which may include removing/destroying
     * Principal and Credential information
     * from the Subject and state cleanup.
     *
     * 
 Note that this method invokes all LoginModules configured for the
     * application regardless of their respective
     * Configuration flag parameters.  Essentially this means
     * that Requisite and Sufficient semantics are
     * ignored for this method.  This guarantees that proper cleanup
     * and state restoration can take place.
     * 
     * 
* * @exception LoginException if the logout fails. */ public void logout() throws LoginException { if (subject == null) { throw new LoginException(ResourcesMgr.getString ("null subject - logout called before login")); } if (configProvided) { // module invoked in doPrivileged with creatorAcc invokeCreatorPriv(LOGOUT_METHOD); } else { // module invoked in doPrivileged invokePriv(LOGOUT_METHOD); } } /** * Return the authenticated Subject. * *
* * @return the authenticated Subject. If the caller specified a * Subject to this LoginContext's constructor, * this method returns the caller-specified Subject. * If a Subject was not specified and authentication succeeds, * this method returns the Subject instantiated and used for * authentication by this LoginContext. * If a Subject was not specified, and authentication fails or * has not been attempted, this method returns null. */ public Subject getSubject() { if (!loginSucceeded && !subjectProvided) return null; return subject; } private void clearState() { moduleIndex = 0; firstError = null; firstRequiredError = null; success = false; } private void throwException(LoginException originalError, LoginException le) throws LoginException { // first clear state clearState(); // throw the exception LoginException error = (originalError != null) ? originalError : le; throw error; } /** * Invokes the login, commit, and logout methods * from a LoginModule inside a doPrivileged block. * * This version is called if the caller did not instantiate * the LoginContext with a Configuration object. */ private void invokePriv(final String methodName) throws LoginException { try { java.security.AccessController.doPrivileged (new java.security.PrivilegedExceptionAction() { public Object run() throws LoginException { invoke(methodName); return null; } }); } catch (java.security.PrivilegedActionException pae) { throw (LoginException)pae.getException(); } } /** * Invokes the login, commit, and logout methods * from a LoginModule inside a doPrivileged block restricted * by creatorAcc * * This version is called if the caller instantiated * the LoginContext with a Configuration object. */ private void invokeCreatorPriv(final String methodName) throws LoginException { try { java.security.AccessController.doPrivileged (new java.security.PrivilegedExceptionAction() { public Object run() throws LoginException { invoke(methodName); return null; } }, creatorAcc); } catch (java.security.PrivilegedActionException pae) { throw (LoginException)pae.getException(); } } private void invoke(String methodName) throws LoginException { // start at moduleIndex // - this can only be non-zero if methodName is LOGIN_METHOD for (int i = moduleIndex; i < moduleStack.length; i++, moduleIndex++) { try { int mIndex = 0; Method[] methods = null; if (moduleStack[i].module != null) { methods = moduleStack[i].module.getClass().getMethods(); } else { // instantiate the LoginModule Class c = Class.forName (moduleStack[i].entry.getLoginModuleName(), true, contextClassLoader); Constructor constructor = c.getConstructor(PARAMS); Object[] args = { }; // allow any object to be a LoginModule // as long as it conforms to the interface moduleStack[i].module = constructor.newInstance(args); methods = moduleStack[i].module.getClass().getMethods(); // call the LoginModule's initialize method for (mIndex = 0; mIndex < methods.length; mIndex++) { if (methods[mIndex].getName().equals(INIT_METHOD)) break; } Object[] initArgs = {subject, callbackHandler, state, moduleStack[i].entry.getOptions() }; // invoke the LoginModule initialize method methods[mIndex].invoke(moduleStack[i].module, initArgs); } // find the requested method in the LoginModule for (mIndex = 0; mIndex < methods.length; mIndex++) { if (methods[mIndex].getName().equals(methodName)) break; } // set up the arguments to be passed to the LoginModule method Object[] args = { }; // invoke the LoginModule method boolean status = ((Boolean)methods[mIndex].invoke (moduleStack[i].module, args)).booleanValue(); if (status == true) { // if SUFFICIENT, return if no prior REQUIRED errors if (!methodName.equals(ABORT_METHOD) && !methodName.equals(LOGOUT_METHOD) && moduleStack[i].entry.getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT && firstRequiredError == null) { // clear state clearState(); if (debug != null) debug.println(methodName + " SUFFICIENT success"); return; } if (debug != null) debug.println(methodName + " success"); success = true; } else { if (debug != null) debug.println(methodName + " ignored"); } } catch (NoSuchMethodException nsme) { MessageFormat form = new MessageFormat(ResourcesMgr.getString ("unable to instantiate LoginModule, module, because " + "it does not provide a no-argument constructor")); Object[] source = {moduleStack[i].entry.getLoginModuleName()}; throwException(null, new LoginException(form.format(source))); } catch (InstantiationException ie) { throwException(null, new LoginException(ResourcesMgr.getString ("unable to instantiate LoginModule: ") + ie.getMessage())); } catch (ClassNotFoundException cnfe) { throwException(null, new LoginException(ResourcesMgr.getString ("unable to find LoginModule class: ") + cnfe.getMessage())); } catch (IllegalAccessException iae) { throwException(null, new LoginException(ResourcesMgr.getString ("unable to access LoginModule: ") + iae.getMessage())); } catch (InvocationTargetException ite) { // failure cases LoginException le; if (ite.getCause() instanceof PendingException && methodName.equals(LOGIN_METHOD)) { // XXX // // if a module's LOGIN_METHOD threw a PendingException // then immediately throw it. // // when LoginContext is called again, // the module that threw the exception is invoked first // (the module list is not invoked from the start). // previously thrown exception state is still present. // // it is assumed that the module which threw // the exception can have its // LOGIN_METHOD invoked twice in a row // without any commit/abort in between. // // in all cases when LoginContext returns // (either via natural return or by throwing an exception) // we need to call clearState before returning. // the only time that is not true is in this case - // do not call throwException here. throw (PendingException)ite.getCause(); } else if (ite.getCause() instanceof LoginException) { le = (LoginException)ite.getCause(); } else if (ite.getCause() instanceof SecurityException) { // do not want privacy leak // (e.g., sensitive file path in exception msg) le = new LoginException("Security Exception"); le.initCause(new SecurityException()); if (debug != null) { debug.println ("original security exception with detail msg " + "replaced by new exception with empty detail msg"); debug.println("original security exception: " + ite.getCause().toString()); } } else { // capture an unexpected LoginModule exception java.io.StringWriter sw = new java.io.StringWriter(); ite.getCause().printStackTrace (new java.io.PrintWriter(sw)); sw.flush(); le = new LoginException(sw.toString()); } if (moduleStack[i].entry.getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.REQUISITE) { if (debug != null) debug.println(methodName + " REQUISITE failure"); // if REQUISITE, then immediately throw an exception if (methodName.equals(ABORT_METHOD) || methodName.equals(LOGOUT_METHOD)) { if (firstRequiredError == null) firstRequiredError = le; } else { throwException(firstRequiredError, le); } } else if (moduleStack[i].entry.getControlFlag() == AppConfigurationEntry.LoginModuleControlFlag.REQUIRED) { if (debug != null) debug.println(methodName + " REQUIRED failure"); // mark down that a REQUIRED module failed if (firstRequiredError == null) firstRequiredError = le; } else { if (debug != null) debug.println(methodName + " OPTIONAL failure"); // mark down that an OPTIONAL module failed if (firstError == null) firstError = le; } } } // we went thru all the LoginModules. if (firstRequiredError != null) { // a REQUIRED module failed -- return the error throwException(firstRequiredError, null); } else if (success == false && firstError != null) { // no module succeeded -- return the first error throwException(firstError, null); } else if (success == false) { // no module succeeded -- all modules were IGNORED throwException(new LoginException (ResourcesMgr.getString("Login Failure: all modules ignored")), null); } else { // success clearState(); return; } } /** * Wrap the caller-specified CallbackHandler in our own * and invoke it within a privileged block, constrained by * the caller's AccessControlContext. */ private static class SecureCallbackHandler implements CallbackHandler { private final java.security.AccessControlContext acc; private final CallbackHandler ch; SecureCallbackHandler(java.security.AccessControlContext acc, CallbackHandler ch) { this.acc = acc; this.ch = ch; } public void handle(final Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException { try { java.security.AccessController.doPrivileged (new java.security.PrivilegedExceptionAction() { public Object run() throws java.io.IOException, UnsupportedCallbackException { ch.handle(callbacks); return null; } }, acc); } catch (java.security.PrivilegedActionException pae) { if (pae.getException() instanceof java.io.IOException) { throw (java.io.IOException)pae.getException(); } else { throw (UnsupportedCallbackException)pae.getException(); } } } } /** * LoginModule information - * incapsulates Configuration info and actual module instances */ private static class ModuleInfo { AppConfigurationEntry entry; Object module; ModuleInfo(AppConfigurationEntry newEntry, Object newModule) { this.entry = newEntry; this.module = newModule; } } }