- /*
- * @(#)KeyStoreLoginModule.java 1.18 04/05/05
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package com.sun.security.auth.module;
-
- import javax.security.auth.x500.X500Principal;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.PushbackInputStream;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.security.AuthProvider;
- import java.security.GeneralSecurityException;
- import java.security.Key;
- import java.security.KeyStore;
- import java.security.KeyStoreException;
- import java.security.NoSuchAlgorithmException;
- import java.security.NoSuchProviderException;
- import java.security.Principal;
- import java.security.PrivateKey;
- import java.security.Provider;
- import java.security.UnrecoverableKeyException;
- import java.security.cert.*;
- import java.security.cert.X509Certificate;
- import java.util.Arrays;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.Map;
- import java.util.ResourceBundle;
- import javax.security.auth.Destroyable;
- import javax.security.auth.DestroyFailedException;
- import javax.security.auth.Subject;
- import javax.security.auth.x500.*;
- import javax.security.auth.Subject;
- import javax.security.auth.x500.*;
- import javax.security.auth.callback.Callback;
- import javax.security.auth.callback.CallbackHandler;
- import javax.security.auth.callback.ConfirmationCallback;
- import javax.security.auth.callback.NameCallback;
- import javax.security.auth.callback.PasswordCallback;
- import javax.security.auth.callback.TextOutputCallback;
- import javax.security.auth.callback.UnsupportedCallbackException;
- import javax.security.auth.login.FailedLoginException;
- import javax.security.auth.login.LoginException;
- import javax.security.auth.spi.LoginModule;
-
- import sun.security.util.AuthResources;
- import sun.security.util.Password;
-
- /**
- * Provides a JAAS login module that prompts for a key store alias and
- * populates the subject with the alias's principal and credentials. Stores
- * an <code>X500Principal</code> for the subject distinguished name of the
- * first certificate in the alias's credentials in the subject's principals,
- * the alias's certificate path in the subject's public credentials, and a
- * <code>X500PrivateCredential</code> whose certificate is the first
- * certificate in the alias's certificate path and whose private key is the
- * alias's private key in the subject's private credentials. <p>
- *
- * Recognizes the following options in the configuration file:
- * <dl>
- *
- * <dt> <code>keyStoreURL</code> </dt>
- * <dd> A URL that specifies the location of the key store. Defaults to
- * a URL pointing to the .keystore file in the directory specified by the
- * <code>user.home</code> system property. The input stream from this
- * URL is passed to the <code>KeyStore.load</code> method.
- * "NONE" may be specified if a <code>null</code> stream must be
- * passed to the <code>KeyStore.load</code> method.
- * "NONE" should be specified if the KeyStore resides
- * on a hardware token device, for example.</dd>
- *
- * <dt> <code>keyStoreType</code> </dt>
- * <dd> The key store type. If not specified, defaults to the result of
- * calling <code>KeyStore.getDefaultType()</code>.
- * If the type is "PKCS11", then keyStoreURL must be "NONE"
- * and privateKeyPasswordURL must not be specified.</dd>
- *
- * <dt> <code>keyStoreProvider</code> </dt>
- * <dd> The key store provider. If not specified, uses the standard search
- * order to find the provider. </dd>
- *
- * <dt> <code>keyStoreAlias</code> </dt>
- * <dd> The alias in the key store to login as. Required when no callback
- * handler is provided. No default value. </dd>
- *
- * <dt> <code>keyStorePasswordURL</code> </dt>
- * <dd> A URL that specifies the location of the key store password. Required
- * when no callback handler is provided and
- * <code>protected</code> is false.
- * No default value. </dd>
- *
- * <dt> <code>privateKeyPasswordURL</code> </dt>
- * <dd> A URL that specifies the location of the specific private key password
- * needed to access the private key for this alias.
- * The keystore password
- * is used if this value is needed and not specified. </dd>
- *
- * <dt> <code>protected</code> </dt>
- * <dd> This value should be set to "true" if the KeyStore
- * has a separate, protected authentication path
- * (for example, a dedicated PIN-pad attached to a smart card).
- * Defaults to "false". If "true" keyStorePasswordURL and
- * privateKeyPasswordURL must not be specified.</dd>
- *
- * </dl>
- */
- public class KeyStoreLoginModule implements LoginModule {
-
- static final java.util.ResourceBundle rb =
- java.util.ResourceBundle.getBundle("sun.security.util.AuthResources");
-
- /* -- Fields -- */
-
- private static final int UNINITIALIZED = 0;
- private static final int INITIALIZED = 1;
- private static final int AUTHENTICATED = 2;
- private static final int LOGGED_IN = 3;
-
- private static final int PROTECTED_PATH = 0;
- private static final int TOKEN = 1;
- private static final int NORMAL = 2;
-
- private static final String NONE = "NONE";
- private static final String P11KEYSTORE = "PKCS11";
-
- private static final TextOutputCallback bannerCallback =
- new TextOutputCallback
- (TextOutputCallback.INFORMATION,
- rb.getString("Please enter keystore information"));
- private final ConfirmationCallback confirmationCallback =
- new ConfirmationCallback
- (ConfirmationCallback.INFORMATION,
- ConfirmationCallback.OK_CANCEL_OPTION,
- ConfirmationCallback.OK);
-
- private Subject subject;
- private CallbackHandler callbackHandler;
- private Map sharedState;
- private Map options;
-
- private char[] keyStorePassword;
- private char[] privateKeyPassword;
- private KeyStore keyStore;
-
- private String keyStoreURL;
- private String keyStoreType;
- private String keyStoreProvider;
- private String keyStoreAlias;
- private String keyStorePasswordURL;
- private String privateKeyPasswordURL;
- private boolean debug;
- private javax.security.auth.x500.X500Principal principal;
- private Certificate[] fromKeyStore;
- private java.security.cert.CertPath certP = null;
- private X500PrivateCredential privateCredential;
- private int status = UNINITIALIZED;
- private boolean nullStream = false;
- private boolean token = false;
- private boolean protectedPath = false;
-
- /* -- Methods -- */
-
- /**
- * Initialize this <code>LoginModule</code>.
- *
- * <p>
- *
- * @param subject the <code>Subject</code> to be authenticated. <p>
- *
- * @param callbackHandler a <code>CallbackHandler</code> for communicating
- * with the end user (prompting for usernames and
- * passwords, for example),
- * which may be <code>null</code>. <p>
- *
- * @param sharedState shared <code>LoginModule</code> state. <p>
- *
- * @param options options specified in the login
- * <code>Configuration</code> for this particular
- * <code>LoginModule</code>.
- */
-
- public void initialize(Subject subject,
- CallbackHandler callbackHandler,
- Map<String,?> sharedState,
- Map<String,?> options)
- {
- this.subject = subject;
- this.callbackHandler = callbackHandler;
- this.sharedState = sharedState;
- this.options = options;
-
- processOptions();
- status = INITIALIZED;
- }
-
- private void processOptions() {
- keyStoreURL = (String) options.get("keyStoreURL");
- if (keyStoreURL == null) {
- keyStoreURL =
- "file:" +
- System.getProperty("user.home").replace(
- File.separatorChar, '/') +
- '/' + ".keystore";
- } else if (NONE.equals(keyStoreURL)) {
- nullStream = true;
- }
- keyStoreType = (String) options.get("keyStoreType");
- if (keyStoreType == null) {
- keyStoreType = KeyStore.getDefaultType();
- }
- if (P11KEYSTORE.equalsIgnoreCase(keyStoreType)) {
- token = true;
- }
-
- keyStoreProvider = (String) options.get("keyStoreProvider");
-
- keyStoreAlias = (String) options.get("keyStoreAlias");
-
- keyStorePasswordURL = (String) options.get("keyStorePasswordURL");
-
- privateKeyPasswordURL = (String) options.get("privateKeyPasswordURL");
-
- protectedPath = "true".equalsIgnoreCase((String)options.get
- ("protected"));
-
- debug = "true".equalsIgnoreCase((String) options.get("debug"));
- if (debug) {
- debugPrint(null);
- debugPrint("keyStoreURL=" + keyStoreURL);
- debugPrint("keyStoreType=" + keyStoreType);
- debugPrint("keyStoreProvider=" + keyStoreProvider);
- debugPrint("keyStoreAlias=" + keyStoreAlias);
- debugPrint("keyStorePasswordURL=" + keyStorePasswordURL);
- debugPrint("privateKeyPasswordURL=" + privateKeyPasswordURL);
- debugPrint("protectedPath=" + protectedPath);
- debugPrint(null);
- }
- }
-
- /**
- * Authenticate the user.
- *
- * <p> Get the Keystore alias and relevant passwords.
- * Retrieve the alias's principal and credentials from the Keystore.
- *
- * <p>
- *
- * @exception FailedLoginException if the authentication fails. <p>
- *
- * @return true in all cases (this <code>LoginModule</code>
- * should not be ignored).
- */
-
- public boolean login() throws LoginException {
- switch (status) {
- case UNINITIALIZED:
- default:
- throw new LoginException("The login module is not initialized");
- case INITIALIZED:
- case AUTHENTICATED:
-
- if (token && !nullStream) {
- throw new LoginException
- ("if keyStoreType is " + P11KEYSTORE +
- " then keyStoreURL must be " + NONE);
- }
-
- if (token && privateKeyPasswordURL != null) {
- throw new LoginException
- ("if keyStoreType is " + P11KEYSTORE +
- " then privateKeyPasswordURL must not be specified");
- }
-
- if (protectedPath &&
- (keyStorePasswordURL != null ||
- privateKeyPasswordURL != null)) {
- throw new LoginException
- ("if protected is true then keyStorePasswordURL and " +
- "privateKeyPasswordURL must not be specified");
- }
-
- // get relevant alias and password info
-
- if (protectedPath) {
- getAliasAndPasswords(PROTECTED_PATH);
- } else if (token) {
- getAliasAndPasswords(TOKEN);
- } else {
- getAliasAndPasswords(NORMAL);
- }
-
- // log into KeyStore to retrieve data,
- // then clear passwords
-
- try {
- getKeyStoreInfo();
- } finally {
- if (privateKeyPassword != null &&
- privateKeyPassword != keyStorePassword) {
- Arrays.fill(privateKeyPassword, '\0');
- privateKeyPassword = null;
- }
- if (keyStorePassword != null) {
- Arrays.fill(keyStorePassword, '\0');
- keyStorePassword = null;
- }
- }
- status = AUTHENTICATED;
- return true;
- case LOGGED_IN:
- return true;
- }
- }
-
- /** Get the alias and passwords to use for looking up in the KeyStore. */
- private void getAliasAndPasswords(int env) throws LoginException {
- if (callbackHandler == null) {
-
- // No callback handler - check for alias and password options
-
- switch (env) {
- case PROTECTED_PATH:
- checkAlias();
- break;
- case TOKEN:
- checkAlias();
- checkStorePass();
- break;
- case NORMAL:
- checkAlias();
- checkStorePass();
- checkKeyPass();
- break;
- }
-
- } else {
-
- // Callback handler available - prompt for alias and passwords
-
- NameCallback aliasCallback;
- if (keyStoreAlias == null || keyStoreAlias.length() == 0) {
- aliasCallback = new NameCallback(
- rb.getString("Keystore alias: "));
- } else {
- aliasCallback =
- new NameCallback(rb.getString("Keystore alias: "),
- keyStoreAlias);
- }
-
- PasswordCallback storePassCallback = null;
- PasswordCallback keyPassCallback = null;
-
- switch (env) {
- case PROTECTED_PATH:
- break;
- case NORMAL:
- keyPassCallback = new PasswordCallback
- (rb.getString("Private key password (optional): "), false);
- // fall thru
- case TOKEN:
- storePassCallback = new PasswordCallback
- (rb.getString("Keystore password: "), false);
- break;
- }
- prompt(aliasCallback, storePassCallback, keyPassCallback);
- }
-
- if (debug) {
- debugPrint("alias=" + keyStoreAlias);
- }
- }
-
- private void checkAlias() throws LoginException {
- if (keyStoreAlias == null) {
- throw new LoginException
- ("Need to specify an alias option to use " +
- "KeyStoreLoginModule non-interactively.");
- }
- }
-
- private void checkStorePass() throws LoginException {
- if (keyStorePasswordURL == null) {
- throw new LoginException
- ("Need to specify keyStorePasswordURL option to use " +
- "KeyStoreLoginModule non-interactively.");
- }
- try {
- InputStream in = new URL(keyStorePasswordURL).openStream();
- keyStorePassword = Password.readPassword(in);
- in.close();
- } catch (IOException e) {
- LoginException le = new LoginException
- ("Problem accessing keystore password \"" +
- keyStorePasswordURL + "\"");
- le.initCause(e);
- throw le;
- }
- }
-
- private void checkKeyPass() throws LoginException {
- if (privateKeyPasswordURL == null) {
- privateKeyPassword = keyStorePassword;
- } else {
- try {
- InputStream in = new URL(privateKeyPasswordURL).openStream();
- privateKeyPassword = Password.readPassword(in);
- in.close();
- } catch (IOException e) {
- LoginException le = new LoginException
- ("Problem accessing private key password \"" +
- privateKeyPasswordURL + "\"");
- le.initCause(e);
- throw le;
- }
- }
- }
-
- private void prompt(NameCallback aliasCallback,
- PasswordCallback storePassCallback,
- PasswordCallback keyPassCallback)
- throws LoginException {
-
- if (storePassCallback == null) {
-
- // only prompt for alias
-
- try {
- callbackHandler.handle(
- new Callback[] {
- bannerCallback, aliasCallback, confirmationCallback
- });
- } catch (IOException e) {
- LoginException le = new LoginException
- ("Problem retrieving keystore alias");
- le.initCause(e);
- throw le;
- } catch (UnsupportedCallbackException e) {
- throw new LoginException(
- "Error: " + e.getCallback().toString() +
- " is not available to retrieve authentication " +
- " information from the user");
- }
-
- int confirmationResult = confirmationCallback.getSelectedIndex();
-
- if (confirmationResult == ConfirmationCallback.CANCEL) {
- throw new LoginException("Login cancelled");
- }
-
- saveAlias(aliasCallback);
-
- } else if (keyPassCallback == null) {
-
- // prompt for alias and key store password
-
- try {
- callbackHandler.handle(
- new Callback[] {
- bannerCallback, aliasCallback,
- storePassCallback, confirmationCallback
- });
- } catch (IOException e) {
- LoginException le = new LoginException
- ("Problem retrieving keystore alias and password");
- le.initCause(e);
- throw le;
- } catch (UnsupportedCallbackException e) {
- throw new LoginException(
- "Error: " + e.getCallback().toString() +
- " is not available to retrieve authentication " +
- " information from the user");
- }
-
- int confirmationResult = confirmationCallback.getSelectedIndex();
-
- if (confirmationResult == ConfirmationCallback.CANCEL) {
- throw new LoginException("Login cancelled");
- }
-
- saveAlias(aliasCallback);
- saveStorePass(storePassCallback);
-
- } else {
-
- // prompt for alias, key store password, and key password
-
- try {
- callbackHandler.handle(
- new Callback[] {
- bannerCallback, aliasCallback,
- storePassCallback, keyPassCallback,
- confirmationCallback
- });
- } catch (IOException e) {
- LoginException le = new LoginException
- ("Problem retrieving keystore alias and passwords");
- le.initCause(e);
- throw le;
- } catch (UnsupportedCallbackException e) {
- throw new LoginException(
- "Error: " + e.getCallback().toString() +
- " is not available to retrieve authentication " +
- " information from the user");
- }
-
- int confirmationResult = confirmationCallback.getSelectedIndex();
-
- if (confirmationResult == ConfirmationCallback.CANCEL) {
- throw new LoginException("Login cancelled");
- }
-
- saveAlias(aliasCallback);
- saveStorePass(storePassCallback);
- saveKeyPass(keyPassCallback);
- }
- }
-
- private void saveAlias(NameCallback cb) {
- keyStoreAlias = cb.getName();
- }
-
- private void saveStorePass(PasswordCallback c) {
- keyStorePassword = c.getPassword();
- if (keyStorePassword == null) {
- /* Treat a NULL password as an empty password */
- keyStorePassword = new char[0];
- }
- c.clearPassword();
- }
-
- private void saveKeyPass(PasswordCallback c) {
- privateKeyPassword = c.getPassword();
- if (privateKeyPassword == null || privateKeyPassword.length == 0) {
- /*
- * Use keystore password if no private key password is
- * specified.
- */
- privateKeyPassword = keyStorePassword;
- }
- c.clearPassword();
- }
-
- /** Get the credentials from the KeyStore. */
- private void getKeyStoreInfo() throws LoginException {
-
- /* Get KeyStore instance */
- try {
- if (keyStoreProvider == null) {
- keyStore = KeyStore.getInstance(keyStoreType);
- } else {
- keyStore =
- KeyStore.getInstance(keyStoreType, keyStoreProvider);
- }
- } catch (KeyStoreException e) {
- LoginException le = new LoginException
- ("The specified keystore type was not available");
- le.initCause(e);
- throw le;
- } catch (NoSuchProviderException e) {
- LoginException le = new LoginException
- ("The specified keystore provider was not available");
- le.initCause(e);
- throw le;
- }
-
- /* Load KeyStore contents from file */
- try {
- if (nullStream) {
- // if using protected auth path, keyStorePassword will be null
- keyStore.load(null, keyStorePassword);
- } else {
- InputStream in = new URL(keyStoreURL).openStream();
- keyStore.load(in, keyStorePassword);
- in.close();
- }
- } catch (MalformedURLException e) {
- LoginException le = new LoginException
- ("Incorrect keyStoreURL option");
- le.initCause(e);
- throw le;
- } catch (GeneralSecurityException e) {
- LoginException le = new LoginException
- ("Error initializing keystore");
- le.initCause(e);
- throw le;
- } catch (IOException e) {
- LoginException le = new LoginException
- ("Error initializing keystore");
- le.initCause(e);
- throw le;
- }
-
- /* Get certificate chain and create a certificate path */
- try {
- fromKeyStore =
- keyStore.getCertificateChain(keyStoreAlias);
- if (fromKeyStore == null
- || fromKeyStore.length == 0
- || !(fromKeyStore[0] instanceof X509Certificate))
- {
- throw new FailedLoginException(
- "Unable to find X.509 certificate chain in keystore");
- } else {
- LinkedList certList = new LinkedList();
- for (int i=0; i < fromKeyStore.length; i++) {
- certList.add(fromKeyStore[i]);
- }
- CertificateFactory certF=
- CertificateFactory.getInstance("X.509");
- certP =
- certF.generateCertPath(certList);
- }
- } catch (KeyStoreException e) {
- LoginException le = new LoginException("Error using keystore");
- le.initCause(e);
- throw le;
- } catch (CertificateException ce) {
- LoginException le = new LoginException
- ("Error: X.509 Certificate type unavailable");
- le.initCause(ce);
- throw le;
- }
-
- /* Get principal and keys */
- try {
- X509Certificate certificate = (X509Certificate)fromKeyStore[0];
- principal = new javax.security.auth.x500.X500Principal
- (certificate.getSubjectDN().getName());
-
- // if token, privateKeyPassword will be null
- Key privateKey = keyStore.getKey(keyStoreAlias, privateKeyPassword);
- if (privateKey == null
- || !(privateKey instanceof PrivateKey))
- {
- throw new FailedLoginException(
- "Unable to recover key from keystore");
- }
-
- privateCredential = new X500PrivateCredential(
- certificate, (PrivateKey) privateKey, keyStoreAlias);
- } catch (KeyStoreException e) {
- LoginException le = new LoginException("Error using keystore");
- le.initCause(e);
- throw le;
- } catch (NoSuchAlgorithmException e) {
- LoginException le = new LoginException("Error using keystore");
- le.initCause(e);
- throw le;
- } catch (UnrecoverableKeyException e) {
- FailedLoginException fle = new FailedLoginException
- ("Unable to recover key from keystore");
- fle.initCause(e);
- throw fle;
- }
- if (debug) {
- debugPrint("principal=" + principal +
- "\n certificate="
- + privateCredential.getCertificate() +
- "\n alias =" + privateCredential.getAlias());
- }
- }
-
- /**
- * Abstract method to commit the authentication process (phase 2).
- *
- * <p> This method is called if the LoginContext's
- * overall authentication succeeded
- * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
- * succeeded).
- *
- * <p> If this LoginModule's own authentication attempt
- * succeeded (checked by retrieving the private state saved by the
- * <code>login</code> method), then this method associates a
- * <code>X500Principal</code> for the subject distinguished name of the
- * first certificate in the alias's credentials in the subject's
- * principals,the alias's certificate path in the subject's public
- * credentials, and a<code>X500PrivateCredential</code> whose certificate
- * is the first certificate in the alias's certificate path and whose
- * private key is the alias's private key in the subject's private
- * credentials. If this LoginModule's own
- * authentication attempted failed, then this method removes
- * any state that was originally saved.
- *
- * <p>
- *
- * @exception LoginException if the commit fails
- *
- * @return true if this LoginModule's own login and commit
- * attempts succeeded, or false otherwise.
- */
-
- public boolean commit() throws LoginException {
- switch (status) {
- case UNINITIALIZED:
- default:
- throw new LoginException("The login module is not initialized");
- case INITIALIZED:
- logoutInternal();
- throw new LoginException("Authentication failed");
- case AUTHENTICATED:
- if (commitInternal()) {
- return true;
- } else {
- logoutInternal();
- throw new LoginException("Unable to retrieve certificates");
- }
- case LOGGED_IN:
- return true;
- }
- }
-
- private boolean commitInternal() throws LoginException {
- /* If the subject is not readonly add to the principal and credentials
- * set; otherwise just return true
- */
- if (subject.isReadOnly()) {
- throw new LoginException ("Subject is set readonly");
- } else {
- subject.getPrincipals().add(principal);
- subject.getPublicCredentials().add(certP);
- subject.getPrivateCredentials().add(privateCredential);
- status = LOGGED_IN;
- return true;
- }
- }
-
- /**
- * <p> This method is called if the LoginContext's
- * overall authentication failed.
- * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
- * did not succeed).
- *
- * <p> If this LoginModule's own authentication attempt
- * succeeded (checked by retrieving the private state saved by the
- * <code>login</code> and <code>commit</code> methods),
- * then this method cleans up any state that was originally saved.
- *
- * <p> If the loaded KeyStore's provider extends
- * <code>java.security.AuthProvider</code>,
- * then the provider's <code>logout</code> method is invoked.
- *
- * <p>
- *
- * @exception LoginException if the abort fails.
- *
- * @return false if this LoginModule's own login and/or commit attempts
- * failed, and true otherwise.
- */
-
- public boolean abort() throws LoginException {
- switch (status) {
- case UNINITIALIZED:
- default:
- return false;
- case INITIALIZED:
- return false;
- case AUTHENTICATED:
- logoutInternal();
- return true;
- case LOGGED_IN:
- logoutInternal();
- return true;
- }
- }
- /**
- * Logout a user.
- *
- * <p> This method removes the Principals, public credentials and the
- * private credentials that were added by the <code>commit</code> method.
- *
- * <p> If the loaded KeyStore's provider extends
- * <code>java.security.AuthProvider</code>,
- * then the provider's <code>logout</code> method is invoked.
- *
- * <p>
- *
- * @exception LoginException if the logout fails.
- *
- * @return true in all cases since this <code>LoginModule</code>
- * should not be ignored.
- */
-
- public boolean logout() throws LoginException {
- if (debug)
- debugPrint("Entering logout " + status);
- switch (status) {
- case UNINITIALIZED:
- throw new LoginException
- ("The login module is not initialized");
- case INITIALIZED:
- case AUTHENTICATED:
- default:
- // impossible for LoginModule to be in AUTHENTICATED
- // state
- // assert status != AUTHENTICATED;
- return false;
- case LOGGED_IN:
- logoutInternal();
- return true;
- }
- }
-
- private void logoutInternal() throws LoginException {
- if (debug) {
- debugPrint("Entering logoutInternal");
- }
-
- // assumption is that KeyStore.load did a login -
- // perform explicit logout if possible
- LoginException logoutException = null;
- Provider provider = keyStore.getProvider();
- if (provider instanceof AuthProvider) {
- AuthProvider ap = (AuthProvider)provider;
- try {
- ap.logout();
- if (debug) {
- debugPrint("logged out of KeyStore AuthProvider");
- }
- } catch (LoginException le) {
- // save but continue below
- logoutException = le;
- }
- }
-
- if (subject.isReadOnly()) {
- // attempt to destroy the private credential
- // even if the Subject is read-only
- principal = null;
- certP = null;
- status = INITIALIZED;
- // destroy the private credential
- Iterator it = subject.getPrivateCredentials().iterator();
- while (it.hasNext()) {
- Object obj = it.next();
- if (privateCredential.equals(obj)) {
- privateCredential = null;
- try {
- ((Destroyable)obj).destroy();
- if (debug)
- debugPrint("Destroyed private credential, " +
- obj.getClass().getName());
- break;
- } catch (DestroyFailedException dfe) {
- LoginException le = new LoginException
- ("Unable to destroy private credential, "
- + obj.getClass().getName());
- le.initCause(dfe);
- throw le;
- }
- }
- }
-
- // throw an exception because we can not remove
- // the principal and public credential from this
- // read-only Subject
- throw new LoginException
- ("Unable to remove Principal ("
- + "X500Principal "
- + ") and public credential (certificatepath) "
- + "from read-only Subject");
- }
- if (principal != null) {
- subject.getPrincipals().remove(principal);
- principal = null;
- }
- if (certP != null) {
- subject.getPublicCredentials().remove(certP);
- certP = null;
- }
- if (privateCredential != null) {
- subject.getPrivateCredentials().remove(privateCredential);
- privateCredential = null;
- }
-
- // throw pending logout exception if there is one
- if (logoutException != null) {
- throw logoutException;
- }
- status = INITIALIZED;
- }
-
- private void debugPrint(String message) {
- // we should switch to logging API
- if (message == null) {
- System.err.println();
- } else {
- System.err.println("Debug KeyStoreLoginModule: " + message);
- }
- }
- }