- /*
- * Copyright 2002 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 javax.security.auth.Subject;
- import javax.security.auth.AuthPermission;
- import javax.security.auth.callback.*;
-
- /**
- * <p> The <code>LoginContext</code> class describes the basic methods used
- * to authenticate Subjects and provides a way to develop an
- * application independent of the underlying authentication technology.
- * A <code>Configuration</code> specifies the authentication technology, or
- * <code>LoginModule</code>, to be used with a particular application.
- * Therefore, different LoginModules can be plugged in under an application
- * without requiring any modifications to the application itself.
- *
- * <p> In addition to supporting <i>pluggable</i> authentication, this class
- * also supports the notion of <i>stacked</i> authentication. In other words,
- * an application may be configured to use more than one
- * <code>LoginModule</code>. For example, one could
- * configure both a Kerberos <code>LoginModule</code> and a smart card
- * <code>LoginModule</code> under an application.
- *
- * <p> A typical caller instantiates this class and passes in
- * a <i>name</i> and a <code>CallbackHandler</code>.
- * <code>LoginContext</code> uses the <i>name</i> as the index into the
- * <code>Configuration</code> to determine which LoginModules should be used,
- * and which ones must succeed in order for the overall authentication to
- * succeed. The <code>CallbackHandler</code> 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).
- *
- * <p> Once the caller has instantiated a <code>LoginContext</code>,
- * it invokes the <code>login</code> method to authenticate
- * a <code>Subject</code>. This <code>login</code> method invokes the
- * <code>login</code> method from each of the LoginModules configured for
- * the <i>name</i> specified by the caller. Each <code>LoginModule</code>
- * then performs its respective type of authentication (username/password,
- * smart card pin verification, etc.). Note that the LoginModules will not
- * attempt authentication retries or introduce delays if the authentication
- * fails. Such tasks belong to the caller.
- *
- * <p> Regardless of whether or not the overall authentication succeeded,
- * this <code>login</code> method completes a 2-phase authentication process
- * by then calling either the <code>commit</code> method or the
- * <code>abort</code> method for each of the configured LoginModules.
- * The <code>commit</code> method for each <code>LoginModule</code>
- * gets invoked if the overall authentication succeeded,
- * whereas the <code>abort</code> method for each <code>LoginModule</code>
- * gets invoked if the overall authentication failed.
- * Each successful LoginModule's <code>commit</code>
- * method associates the relevant Principals (authenticated identities)
- * and Credentials (authentication data such as cryptographic keys)
- * with the <code>Subject</code>. Each LoginModule's <code>abort</code>
- * method cleans up or removes/destroys any previously stored authentication
- * state.
- *
- * <p> If the <code>login</code> method returns without
- * throwing an exception, then the overall authentication succeeded.
- * The caller can then retrieve
- * the newly authenticated <code>Subject</code> by invoking the
- * <code>getSubject</code> method. Principals and Credentials associated
- * with the <code>Subject</code> may be retrieved by invoking the Subject's
- * respective <code>getPrincipals</code>, <code>getPublicCredentials</code>,
- * and <code>getPrivateCredentials</code> methods.
- *
- * <p> To logout the <code>Subject</code>, the caller simply needs to
- * invoke the <code>logout</code> method. As with the <code>login</code>
- * method, this <code>logout</code> method invokes the <code>logout</code>
- * method for each <code>LoginModule</code> configured for this
- * <code>LoginContext</code>. Each LoginModule's <code>logout</code>
- * method cleans up state and removes/destroys Principals and Credentials
- * from the <code>Subject</code> as appropriate.
- *
- * <p> Each of the configured LoginModules invoked by the
- * <code>LoginContext</code> is initialized with a
- * <code>Subject</code> to be authenticated, a <code>CallbackHandler</code>
- * used to communicate with users, shared <code>LoginModule</code> state,
- * and LoginModule-specific options.
- * If the <code>LoginContext</code> was not provided a <code>Subject</code>
- * then it instantiates one itself. Each <code>LoginModule</code>
- * which successfully authenticates a user updates the <code>Subject</code>
- * with the relevant user information (Principals and Credentials).
- * This <code>Subject</code> can then be returned via the
- * <code>getSubject</code> method from the <code>LoginContext</code> class
- * if the overall authentication succeeds. Note that LoginModules are always
- * invoked from within an <code>AccessController.doPrivileged</code> call.
- * Therefore, although LoginModules that perform security-sensitive tasks
- * (such as connecting to remote hosts) need to be granted the relevant
- * Permissions in the security <code>Policy</code>, the callers of the
- * LoginModules do not require those Permissions.
- *
- * <p> A <code>LoginContext</code> supports authentication retries
- * by the calling application. For example, a LoginContext's
- * <code>login</code> method may be invoked multiple times
- * if the user incorrectly types in a password. However, a
- * <code>LoginContext</code> should not be used to authenticate
- * more than one <code>Subject</code>. A separate <code>LoginContext</code>
- * should be used to authenticate each different <code>Subject</code>.
- *
- * <p> Multiple calls into the same <code>LoginContext</code>
- * do not affect the <code>LoginModule</code> state, or the
- * LoginModule-specific options.
- *
- * @version 1.79, 01/14/00
- * @see javax.security.auth.Subject
- * @see javax.security.auth.callback.CallbackHandler
- * @see javax.security.auth.login.Configuration
- * @see javax.security.auth.spi.LoginModule
- * @author Li Gong
- */
- public class LoginContext {
-
- private static final java.util.ResourceBundle rb =
- java.util.ResourceBundle.getBundle("com.sun.security.auth.Resources");
-
- 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 Subject subject = null;
- private boolean subjectProvided = false;
- private CallbackHandler callbackHandler;
- private Map state = new HashMap();
-
- private Configuration config;
- private AppConfigurationEntry[] moduleStack;
- private ClassLoader sysClassLoader = null;
- private static final Class[] PARAMS = { };
-
- private static final Debug debug = Debug.getInstance("logincontext",
- "\t[LoginContext]");
-
- private void init(String name) throws LoginException {
-
- java.lang.SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- sm.checkPermission(new AuthPermission("createLoginContext"));
- }
-
- if (name == null)
- throw new LoginException
- (rb.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
- moduleStack = config.getAppConfigurationEntry(name);
- if (moduleStack == null) {
- moduleStack = config.getAppConfigurationEntry(OTHER);
- if (moduleStack == null) {
- throw new LoginException
- (rb.getString("No LoginModules configured for ") +
- name);
- }
- }
-
- sysClassLoader =
- (ClassLoader)java.security.AccessController.doPrivileged
- (new java.security.PrivilegedAction() {
- public Object run() {
- return ClassLoader.getSystemClassLoader();
- }
- });
- }
-
- /**
- * Constructor for the <code>LoginContext</code> class.
- *
- * <p> Initialize the new <code>LoginContext</code> object with a name.
- * <code>LoginContext</code> uses the specified name as the index
- * into the <code>Configuration</code> to determine which LoginModules
- * should be used. If the provided name does not match any in the
- * <code>Configuration</code>, then the <code>LoginContext</code>
- * uses the default <code>Configuration</code> entry, "<i>other</i>".
- * If there is no <code>Configuration</code> entry for "<i>other</i>",
- * then a <code>LoginException</code> is thrown.
- *
- * <p> This constructor does not allow for a
- * <code>CallbackHandler</code>. Therefore the underlying LoginModules
- * will not have a <code>CallbackHandler</code> for use in communicating
- * with users. The caller thus assumes that the configured
- * LoginModules have alternative means for authenticating the user.
- *
- * <p> Since no <code>Subject</code> can be specified to this constructor,
- * it instantiates a <code>Subject</code> itself.
- *
- * <p>
- *
- * @param name the name used as the index into the
- * <code>Configuration</code>.
- *
- * @exception LoginException if the specified <code>name</code>
- * does not appear in the <code>Configuration</code>
- * and there is no <code>Configuration</code> entry
- * for "<i>other</i>".
- */
- public LoginContext(String name) throws LoginException {
- init(name);
- }
-
- /**
- * Constructor for the <code>LoginContext</code> class.
- *
- * <p> Initialize the new <code>LoginContext</code> object with a name
- * and a <code>Subject</code> object.
- *
- * <p> <code>LoginContext</code> uses the name as the index
- * into the <code>Configuration</code> to determine which LoginModules
- * should be used. If the provided name does not match any in the
- * <code>Configuration</code>, then the <code>LoginContext</code>
- * uses the default <code>Configuration</code> entry, "<i>other</i>".
- * If there is no <code>Configuration</code> entry for "<i>other</i>",
- * then a <code>LoginException</code> is thrown.
- *
- * <p> This constructor does not allow for a
- * <code>CallbackHandler</code>. Therefore the underlying LoginModules
- * will not have a <code>CallbackHandler</code> for use in communicating
- * with users. The caller thus assumes that the configured
- * LoginModules have alternative means for authenticating the user.
- *
- * <p> <code>LoginContext</code> passes the <code>Subject</code>
- * object to configured LoginModules so they may perform additional
- * authentication and update the <code>Subject</code> with new
- * Principals and Credentials.
- *
- * <p>
- *
- * @param name the name used as the index into the
- * <code>Configuration</code>. <p>
- *
- * @param subject the <code>Subject</code> to authenticate.
- *
- * @exception LoginException if the specified <code>name</code>
- * does not appear in the <code>Configuration</code>
- * and there is no <code>Configuration</code> entry
- * for "<i>other</i>", or if the specified <code>subject</code>
- * is <code>null</code>.
- */
- public LoginContext(String name, Subject subject)
- throws LoginException {
- init(name);
- if (subject == null)
- throw new LoginException
- (rb.getString("invalid null Subject provided"));
- this.subject = subject;
- subjectProvided = true;
- }
-
- /**
- * Constructor for the <code>LoginContext</code> class.
- *
- * <p> Initialize the new <code>LoginContext</code> object with a name
- * and a <code>CallbackHandler</code> object.
- *
- * <p> <code>LoginContext</code> uses the name as the index
- * into the <code>Configuration</code> to determine which LoginModules
- * should be used. If the provided name does not match any in the
- * <code>Configuration</code>, then the <code>LoginContext</code>
- * uses the default <code>Configuration</code> entry, "<i>other</i>".
- * If there is no <code>Configuration</code> entry for "<i>other</i>",
- * then a <code>LoginException</code> is thrown.
- *
- * <p> <code>LoginContext</code> passes the <code>CallbackHandler</code>
- * object to configured LoginModules so they may communicate with the user.
- * The <code>CallbackHandler</code> object therefore allows LoginModules to
- * remain independent of the different ways applications interact with
- * users. This <code>LoginContext</code> must wrap the
- * application-provided <code>CallbackHandler</code> in a new
- * <code>CallbackHandler</code> implementation, whose <code>handle</code>
- * method implementation invokes the application-provided
- * CallbackHandler's <code>handle</code> method in a
- * <code>java.security.AccessController.doPrivileged</code> call
- * constrained by the caller's current <code>AccessControlContext</code>.
- *
- * <p> Since no <code>Subject</code> can be specified to this constructor,
- * it instantiates a <code>Subject</code> itself.
- *
- * <p>
- *
- * @param name the name used as the index into the
- * <code>Configuration</code>. <p>
- *
- * @param callbackHandler the <code>CallbackHandler</code> object used by
- * LoginModules to communicate with the user.
- *
- * @exception LoginException if the specified <code>name</code>
- * does not appear in the <code>Configuration</code>
- * and there is no <code>Configuration</code> entry
- * for "<i>other</i>", or if the specified
- * <code>callbackHandler</code> is <code>null</code>.
- */
- public LoginContext(String name, CallbackHandler callbackHandler)
- throws LoginException {
- init(name);
- if (callbackHandler == null)
- throw new LoginException
- (rb.getString("invalid null CallbackHandler provided"));
- this.callbackHandler = new SecureCallbackHandler
- (java.security.AccessController.getContext(),
- callbackHandler);
- }
-
- /**
- * Constructor for the <code>LoginContext</code> class.
- *
- * <p> Initialize the new <code>LoginContext</code> object with a name,
- * a <code>Subject</code> to be authenticated, and a
- * <code>CallbackHandler</code> object.
- *
- * <p> <code>LoginContext</code> uses the name as the index
- * into the <code>Configuration</code> to determine which LoginModules
- * should be used. If the provided name does not match any in the
- * <code>Configuration</code>, then the <code>LoginContext</code>
- * uses the default <code>Configuration</code> entry, "<i>other</i>".
- * If there is no <code>Configuration</code> entry for "<i>other</i>",
- * then a <code>LoginException</code> is thrown.
- *
- * <p> <code>LoginContext</code> passes the <code>Subject</code>
- * object to configured LoginModules so they may perform additional
- * authentication and update the <code>Subject</code> with new
- * Principals and Credentials.
- *
- * <p> <code>LoginContext</code> passes the <code>CallbackHandler</code>
- * object to configured LoginModules so they may communicate with the user.
- * The <code>CallbackHandler</code> object therefore allows LoginModules to
- * remain independent of the different ways applications interact with
- * users. This <code>LoginContext</code> must wrap the
- * application-provided <code>CallbackHandler</code> in a new
- * <code>CallbackHandler</code> implementation, whose <code>handle</code>
- * method implementation invokes the application-provided
- * CallbackHandler's <code>handle</code> method in a
- * <code>java.security.AccessController.doPrivileged</code> call
- * constrained by the caller's current <code>AccessControlContext</code>.
- *
- *
- * <p>
- *
- * @param name the name used as the index into the
- * <code>Configuration</code>. <p>
- *
- * @param subject the <code>Subject</code> to authenticate. <p>
- *
- * @param callbackHandler the <code>CallbackHandler</code> object used by
- * LoginModules to communicate with the user.
- *
- * @exception LoginException if the specified <code>name</code>
- * does not appear in the <code>Configuration</code>
- * and there is no <code>Configuration</code> entry
- * for "<i>other</i>", or if the specified <code>subject</code>
- * is <code>null</code>, or if the specified
- * <code>callbackHandler</code> is <code>null</code>.
- */
- public LoginContext(String name, Subject subject,
- CallbackHandler callbackHandler) throws LoginException {
- this(name, subject);
- if (callbackHandler == null)
- throw new LoginException
- (rb.getString("invalid null CallbackHandler provided"));
- this.callbackHandler = new SecureCallbackHandler
- (java.security.AccessController.getContext(),
- callbackHandler);
- }
-
- /**
- * Perform the authentication and, if successful,
- * associate Principals and Credentials with the authenticated
- * <code>Subject</code>.
- *
- * <p> This method invokes the <code>login</code> method for each
- * LoginModule configured for the <i>name</i> provided to the
- * <code>LoginContext</code> constructor, as determined by the login
- * <code>Configuration</code>. Each <code>LoginModule</code>
- * then performs its respective type of authentication
- * (username/password, smart card pin verification, etc.).
- *
- * <p> This method completes a 2-phase authentication process by
- * calling each configured LoginModule's <code>commit</code> method
- * if the overall authentication succeeded (the relevant REQUIRED,
- * REQUISITE, SUFFICIENT, and OPTIONAL LoginModules succeeded),
- * or by calling each configured LoginModule's <code>abort</code> method
- * if the overall authentication failed. If authentication succeeded,
- * each successful LoginModule's <code>commit</code> method associates
- * the relevant Principals and Credentials with the <code>Subject</code>.
- * If authentication failed, each LoginModule's <code>abort</code> method
- * removes/destroys any previously stored state.
- *
- * <p> If the <code>commit</code> phase of the authentication process
- * fails, then the overall authentication fails and this method
- * invokes the <code>abort</code> method for each configured
- * <code>LoginModule</code>.
- *
- * <p> If the <code>abort</code> phase
- * fails for any reason, then this method propagates the
- * original exception thrown either during the <code>login</code> phase
- * or the <code>commit</code> phase. In either case, the overall
- * authentication fails.
- *
- * <p> In the case where multiple LoginModules fail,
- * this method propagates the exception raised by the first
- * <code>LoginModule</code> which failed.
- *
- * <p> Note that if this method enters the <code>abort</code> phase
- * (either the <code>login</code> or <code>commit</code> phase failed),
- * this method invokes all LoginModules configured for the specified
- * application regardless of their respective <code>Configuration</code>
- * flag parameters. Essentially this means that <code>Requisite</code>
- * and <code>Sufficient</code> semantics are ignored during the
- * <code>abort</code> phase. This guarantees that proper cleanup
- * and state restoration can take place.
- *
- * <p>
- *
- * @exception LoginException if the authentication fails.
- */
- public void login() throws LoginException {
-
- Exception firstException = null;
-
- if (subject == null) {
- subject = new Subject();
- }
-
- try {
- invokeModule(LOGIN_METHOD);
- invokeModule(COMMIT_METHOD);
- } catch (LoginException le) {
-
- try {
- invokeModule(ABORT_METHOD);
- } catch (LoginException le2) {
- if (!subjectProvided)
- subject = null;
- throw le;
- }
- if (!subjectProvided)
- subject = null;
- throw le;
- }
- }
-
- /**
- * Logout the <code>Subject</code>.
- *
- * <p> This method invokes the <code>logout</code> method for each
- * <code>LoginModule</code> configured for this <code>LoginContext</code>.
- * Each <code>LoginModule</code> performs its respective logout procedure
- * which may include removing/destroying
- * <code>Principal</code> and <code>Credential</code> information
- * from the <code>Subject</code> and state cleanup.
- *
- * <p> Note that this method invokes all LoginModules configured for the
- * specified application regardless of their respective
- * <code>Configuration</code> flag parameters. Essentially this means
- * that <code>Requisite</code> and <code>Sufficient</code> semantics are
- * ignored for this method. This guarantees that proper cleanup
- * and state restoration can take place.
- *
- * <p>
- *
- * @exception LoginException if the logout fails.
- */
- public void logout() throws LoginException {
- if (subject == null)
- throw new LoginException
- (rb.getString("null subject - logout called before login"));
-
- try {
- invokeModule(LOGOUT_METHOD);
- } catch (LoginException le) {
- if (!subjectProvided)
- subject = null;
- throw le;
- }
- }
-
- /**
- * Return the authenticated Subject.
- *
- * <p>
- *
- * @return the authenticated Subject. If authentication fails
- * and a Subject was not provided to this LoginContext's
- * constructor, this method returns <code>null</code>.
- * Otherwise, this method returns the provided Subject.
- */
- public Subject getSubject() {
- return subject;
- }
-
- private void throwException(LoginException originalError, LoginException le)
- throws LoginException {
- LoginException error = (originalError != null) ? originalError : le;
- throw error;
- }
-
- /**
- * Invokes the login, commit, and logout methods
- * from a LoginModule inside a doPrivileged block.
- */
- private void invokeModule(String methodName) throws LoginException {
- try {
- final String finalName = methodName;
- java.security.AccessController.doPrivileged
- (new java.security.PrivilegedExceptionAction() {
- public Object run() throws LoginException {
- invoke(finalName);
- return null;
- }
- });
- } catch (java.security.PrivilegedActionException pae) {
- throw (LoginException)pae.getException();
- }
- }
-
- private void invoke(String methodName) throws LoginException {
-
- LoginException firstError = null;
- LoginException firstRequiredError = null;
- boolean success = false;
-
- for (int i = 0; i < moduleStack.length; i++) {
-
- 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].getLoginModuleName(),
- true,
- sysClassLoader);
-
- 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].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].getControlFlag() ==
- AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT &&
- firstRequiredError == null) {
-
- 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) {
- throw new LoginException
- (rb.getString("unable to instantiate LoginModule, ") +
- moduleStack[i].getLoginModuleName() +
- rb.getString(", because it does not provide a ") +
- rb.getString("no-argument constructor"));
- } catch (InstantiationException ie) {
- throw new LoginException
- (rb.getString("unable to instantiate LoginModule: ") +
- ie.getMessage());
- } catch (ClassNotFoundException cnfe) {
- throw new LoginException
- (rb.getString("unable to find LoginModule class: ") +
- cnfe.getMessage());
- } catch (IllegalAccessException iae) {
- throw new LoginException
- (rb.getString("unable to access LoginModule: ") +
- iae.getMessage());
- } catch (InvocationTargetException ite) {
-
- // failure cases
- LoginException le;
- if (ite.getTargetException() instanceof LoginException) {
- le = (LoginException)ite.getTargetException();
- } else {
- // capture an unexpected LoginModule exception
- java.io.StringWriter sw = new java.io.StringWriter();
- ite.getTargetException().printStackTrace
- (new java.io.PrintWriter(sw));
- sw.flush();
- le = new LoginException(sw.toString());
- }
-
- if (moduleStack[i].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].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
- (rb.getString("Login Failure: all modules ignored")), null);
- } else {
- // success
- return;
- }
- }
-
- /**
- * Wrap the application-provided CallbackHandler in our own
- * and invoke it within a privileged block, constrained by
- * the caller's AccessControlContext.
- */
- private 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(Callback[] callbacks) throws java.io.IOException,
- UnsupportedCallbackException {
- try {
- final Callback[] finalCallbacks = callbacks;
- java.security.AccessController.doPrivileged
- (new java.security.PrivilegedExceptionAction() {
- public Object run() throws java.io.IOException,
- UnsupportedCallbackException {
- ch.handle(finalCallbacks);
- 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();
- }
- }
- }
- }
- }