996 lines · 40.9 KB · Java
RawDownload
/* * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ 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; /** * <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. * 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. * 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. * * <p> A typical caller instantiates a LoginContext with * a <i>name</i> and a <code>CallbackHandler</code>. * LoginContext uses the <i>name</i> 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 <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 LoginContext, * it invokes the <code>login</code> method to authenticate * a <code>Subject</code>.  The <code>login</code> 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. * * <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 Subject by invoking the * <code>getSubject</code> method.  Principals and Credentials associated * with the Subject may be retrieved by invoking the Subject's * respective <code>getPrincipals</code>, <code>getPublicCredentials</code>, * and <code>getPrivateCredentials</code> methods. * * <p> To logout the Subject, the caller calls * the <code>logout</code> method.  As with the <code>login</code> * method, this <code>logout</code> method invokes the <code>logout</code> * method for the configured modules. * * <p> A LoginContext should not be used to authenticate * more than one Subject.  A separate LoginContext * should be used to authenticate each different Subject. * * <p> The following documentation applies to all LoginContext constructors: * <ol> * * <li> <code>Subject</code> * <ul> * <li> If the constructor has a Subject * input parameter, the LoginContext uses the caller-specified * Subject object. * <p> * <li> If the caller specifies a <code>null</code> Subject * and a <code>null</code> value is permitted, * the LoginContext instantiates a new Subject. * <p> * <li> If the constructor does <b>not</b> have a Subject * input parameter, the LoginContext instantiates a new Subject. * <p> * </ul> * * <li> <code>Configuration</code> * <ul> * <li> If the constructor has a Configuration * input parameter and the caller specifies a non-null Configuration, * the LoginContext uses the caller-specified Configuration. * <p> * If the constructor does <b>not</b> have a Configuration * input parameter, or if the caller specifies a <code>null</code> * Configuration object, the constructor uses the following call to * get the installed Configuration: * <pre> *      config = Configuration.getConfiguration(); * </pre> * For both cases, * the <i>name</i> argument given to the constructor is passed to the * <code>Configuration.getAppConfigurationEntry</code> method. * If the Configuration has no entries for the specified <i>name</i>, * then the <code>LoginContext</code> calls * <code>getAppConfigurationEntry</code> with the name, "<i>other</i>" * (the default entry name).  If there is no entry for "<i>other</i>", * then a <code>LoginException</code> is thrown. * <p> * <li> When LoginContext uses the installed Configuration, the caller * requires the createLoginContext.<em>name</em> and possibly * createLoginContext.other AuthPermissions. Furthermore, the * LoginContext will invoke configured modules from within an * <code>AccessController.doPrivileged</code> 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. * <p> * <li> When LoginContext uses a caller-specified Configuration, the caller * does not require any createLoginContext AuthPermission.  The LoginContext * saves the <code>AccessControlContext</code> for the caller, * and invokes the configured modules from within an * <tt>AccessController.doPrivileged</tt> 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. * <p> * </ul> * * <li> <code>CallbackHandler</code> * <ul> * <li> If the constructor has a CallbackHandler * input parameter, the LoginContext uses the caller-specified * CallbackHandler object. * <p> * <li> If the constructor does <b>not</b> have a CallbackHandler * input parameter, or if the caller specifies a <code>null</code> * CallbackHandler object (and a <code>null</code> value is permitted), * the LoginContext queries the * <i>auth.login.defaultCallbackHandler</i> 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. * * <p> * <li> When the LoginContext uses the installed Configuration (instead of * a caller-specified Configuration, see above), * then this LoginContext must wrap any * caller-specified or default CallbackHandler implementation * in a new CallbackHandler implementation * whose <code>handle</code> method implementation invokes the * specified CallbackHandler's <code>handle</code> method in a * <code>java.security.AccessController.doPrivileged</code> call * constrained by the caller's current <code>AccessControlContext</code>. * </ul> * </ol> * * <p> Note that Security Properties * (such as <code>auth.login.defaultCallbackHandler</code>) * can be set programmatically via the * <code>java.security.Security</code> class, * or statically in the Java security properties file located in the * file named &lt;JAVA_HOME&gt;/lib/security/java.security. * &lt;JAVA_HOME&gt; refers to the value of the java.home system property, * and specifies the directory where the JRE is installed. * * @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 = java.security.AccessController.doPrivileged                (new java.security.PrivilegedAction<Configuration>() {                public Configuration 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 = java.security.AccessController.doPrivileged                (new java.security.PrivilegedAction<ClassLoader>() {                public ClassLoader run() {                    return Thread.currentThread().getContextClassLoader();                }        });    }     private void loadDefaultCallbackHandler() throws LoginException {         // get the default handler class        try {             final ClassLoader finalLoader = contextClassLoader;             this.callbackHandler = java.security.AccessController.doPrivileged(                new java.security.PrivilegedExceptionAction<CallbackHandler>() {                public CallbackHandler 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 (CallbackHandler)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 <code>LoginContext</code> object with a name.     *     * @param name the name used as the index into the     *          <code>Configuration</code>.     *     * @exception LoginException if the caller-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     *          <i>auth.login.defaultCallbackHandler</i>     *          security property was set, but the implementation     *          class could not be loaded.     *          <p>     * @exception SecurityException if a SecurityManager is set and     *          the caller does not have     *          AuthPermission("createLoginContext.<i>name</i>"),     *          or if a configuration entry for <i>name</i> 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 <code>LoginContext</code> object with a name     * and a <code>Subject</code> object.     *     * <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 caller-specified <code>name</code>     *          does not appear in the <code>Configuration</code>     *          and there is no <code>Configuration</code> entry     *          for "<i>other</i>", if the caller-specified <code>subject</code>     *          is <code>null</code>, or if the     *          <i>auth.login.defaultCallbackHandler</i>     *          security property was set, but the implementation     *          class could not be loaded.     *          <p>     * @exception SecurityException if a SecurityManager is set and     *          the caller does not have     *          AuthPermission("createLoginContext.<i>name</i>"),     *          or if a configuration entry for <i>name</i> 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 <code>LoginContext</code> object with a name     * and a <code>CallbackHandler</code> object.     *     * <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 caller-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 caller-specified     *          <code>callbackHandler</code> is <code>null</code>.     *          <p>     * @exception SecurityException if a SecurityManager is set and     *          the caller does not have     *          AuthPermission("createLoginContext.<i>name</i>"),     *          or if a configuration entry for <i>name</i> 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 <code>LoginContext</code> object with a name,     * a <code>Subject</code> to be authenticated, and a     * <code>CallbackHandler</code> object.     *     * <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 caller-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 caller-specified     *          <code>subject</code> is <code>null</code>,     *          or if the caller-specified     *          <code>callbackHandler</code> is <code>null</code>.     *          <p>     * @exception SecurityException if a SecurityManager is set and     *          the caller does not have     *          AuthPermission("createLoginContext.<i>name</i>"),     *          or if a configuration entry for <i>name</i> 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 <code>LoginContext</code> object with a name,     * a <code>Subject</code> to be authenticated,     * a <code>CallbackHandler</code> object, and a login     * <code>Configuration</code>.     *     * <p>     *     * @param name the name used as the index into the caller-specified     *          <code>Configuration</code>. <p>     *     * @param subject the <code>Subject</code> to authenticate,     *          or <code>null</code>. <p>     *     * @param callbackHandler the <code>CallbackHandler</code> object used by     *          LoginModules to communicate with the user, or <code>null</code>.     *          <p>     *     * @param config the <code>Configuration</code> that lists the     *          login modules to be called to perform the authentication,     *          or <code>null</code>.     *     * @exception LoginException if the caller-specified <code>name</code>     *          does not appear in the <code>Configuration</code>     *          and there is no <code>Configuration</code> entry     *          for "<i>other</i>".     *          <p>     * @exception SecurityException if a SecurityManager is set,     *          <i>config</i> is <code>null</code>,     *          and either the caller does not have     *          AuthPermission("createLoginContext.<i>name</i>"),     *          or if a configuration entry for <i>name</i> does not exist and     *          the caller does not additionally have

Lines 1–500 of 996.