Java tutorial
/* * Copyright (c) 1998, 2017, 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 javax.security.auth.AuthPermission; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Provider; import java.security.Security; import java.util.Objects; import sun.security.jca.GetInstance; /** * A Configuration object is responsible for specifying which LoginModules * should be used for a particular application, and in what order the * LoginModules should be invoked. * * <p> A login configuration contains the following information. * Note that this example only represents the default syntax for the * {@code Configuration}. Subclass implementations of this class * may implement alternative syntaxes and may retrieve the * {@code Configuration} from any source such as files, databases, * or servers. * * <pre> * Name { * ModuleClass Flag ModuleOptions; * ModuleClass Flag ModuleOptions; * ModuleClass Flag ModuleOptions; * }; * Name { * ModuleClass Flag ModuleOptions; * ModuleClass Flag ModuleOptions; * }; * other { * ModuleClass Flag ModuleOptions; * ModuleClass Flag ModuleOptions; * }; * </pre> * * <p> Each entry in the {@code Configuration} is indexed via an * application name, <i>Name</i>, and contains a list of * LoginModules configured for that application. Each {@code LoginModule} * is specified via its fully qualified class name. * Authentication proceeds down the module list in the exact order specified. * If an application does not have a specific entry, * it defaults to the specific entry for "<i>other</i>". * * <p> The <i>Flag</i> value controls the overall behavior as authentication * proceeds down the stack. The following represents a description of the * valid values for <i>Flag</i> and their respective semantics: * * <pre> * 1) Required - The {@code LoginModule} is required to succeed. * If it succeeds or fails, authentication still continues * to proceed down the {@code LoginModule} list. * * 2) Requisite - The {@code LoginModule} is required to succeed. * If it succeeds, authentication continues down the * {@code LoginModule} list. If it fails, * control immediately returns to the application * (authentication does not proceed down the * {@code LoginModule} list). * * 3) Sufficient - The {@code LoginModule} is not required to * succeed. If it does succeed, control immediately * returns to the application (authentication does not * proceed down the {@code LoginModule} list). * If it fails, authentication continues down the * {@code LoginModule} list. * * 4) Optional - The {@code LoginModule} is not required to * succeed. If it succeeds or fails, * authentication still continues to proceed down the * {@code LoginModule} list. * </pre> * * <p> The overall authentication succeeds only if all <i>Required</i> and * <i>Requisite</i> LoginModules succeed. If a <i>Sufficient</i> * {@code LoginModule} is configured and succeeds, * then only the <i>Required</i> and <i>Requisite</i> LoginModules prior to * that <i>Sufficient</i> {@code LoginModule} need to have succeeded for * the overall authentication to succeed. If no <i>Required</i> or * <i>Requisite</i> LoginModules are configured for an application, * then at least one <i>Sufficient</i> or <i>Optional</i> * {@code LoginModule} must succeed. * * <p> <i>ModuleOptions</i> is a space separated list of * {@code LoginModule}-specific values which are passed directly to * the underlying LoginModules. Options are defined by the * {@code LoginModule} itself, and control the behavior within it. * For example, a {@code LoginModule} may define options to support * debugging/testing capabilities. The correct way to specify options in the * {@code Configuration} is by using the following key-value pairing: * <i>debug="true"</i>. The key and value should be separated by an * 'equals' symbol, and the value should be surrounded by double quotes. * If a String in the form, ${system.property}, occurs in the value, * it will be expanded to the value of the system property. * Note that there is no limit to the number of * options a {@code LoginModule} may define. * * <p> The following represents an example {@code Configuration} entry * based on the syntax above: * * <pre> * Login { * com.sun.security.auth.module.UnixLoginModule required; * com.sun.security.auth.module.Krb5LoginModule optional * useTicketCache="true" * ticketCache="${user.home}${/}tickets"; * }; * </pre> * * <p> This {@code Configuration} specifies that an application named, * "Login", requires users to first authenticate to the * <i>com.sun.security.auth.module.UnixLoginModule</i>, which is * required to succeed. Even if the <i>UnixLoginModule</i> * authentication fails, the * <i>com.sun.security.auth.module.Krb5LoginModule</i> * still gets invoked. This helps hide the source of failure. * Since the <i>Krb5LoginModule</i> is <i>Optional</i>, the overall * authentication succeeds only if the <i>UnixLoginModule</i> * (<i>Required</i>) succeeds. * * <p> Also note that the LoginModule-specific options, * <i>useTicketCache="true"</i> and * <i>ticketCache=${user.home}${/}tickets"</i>, * are passed to the <i>Krb5LoginModule</i>. * These options instruct the <i>Krb5LoginModule</i> to * use the ticket cache at the specified location. * The system properties, <i>user.home</i> and <i>/</i> * (file.separator), are expanded to their respective values. * * <p> There is only one Configuration object installed in the runtime at any * given time. A Configuration object can be installed by calling the * {@code setConfiguration} method. The installed Configuration object * can be obtained by calling the {@code getConfiguration} method. * * <p> If no Configuration object has been installed in the runtime, a call to * {@code getConfiguration} installs an instance of the default * Configuration implementation (a default subclass implementation of this * abstract class). * The default Configuration implementation can be changed by setting the value * of the {@code login.configuration.provider} security property to the fully * qualified name of the desired Configuration subclass implementation. * * <p> Application code can directly subclass Configuration to provide a custom * implementation. In addition, an instance of a Configuration object can be * constructed by invoking one of the {@code getInstance} factory methods * with a standard type. The default policy type is "JavaLoginConfig". * See the Configuration section in the <a href= * "{@docRoot}/../specs/security/standard-names.html#configuration-types"> * Java Security Standard Algorithm Names Specification</a> * for a list of standard Configuration types. * * @since 1.4 * @see javax.security.auth.login.LoginContext * @see java.security.Security security properties */ public abstract class Configuration { private static Configuration configuration; private final java.security.AccessControlContext acc = java.security.AccessController.getContext(); private static void checkPermission(String type) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new AuthPermission("createLoginConfiguration." + type)); } } /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ protected Configuration() { } /** * Get the installed login Configuration. * * @return the login Configuration. If a Configuration object was set * via the {@code Configuration.setConfiguration} method, * then that object is returned. Otherwise, a default * Configuration object is returned. * * @exception SecurityException if the caller does not have permission * to retrieve the Configuration. * * @see #setConfiguration */ public static Configuration getConfiguration() { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(new AuthPermission("getLoginConfiguration")); synchronized (Configuration.class) { if (configuration == null) { String config_class = null; config_class = AccessController.doPrivileged(new PrivilegedAction<>() { public String run() { return java.security.Security.getProperty("login.configuration.provider"); } }); if (config_class == null) { config_class = "sun.security.provider.ConfigFile"; } try { final String finalClass = config_class; Configuration untrustedImpl = AccessController.doPrivileged(new PrivilegedExceptionAction<>() { public Configuration run() throws ClassNotFoundException, InstantiationException, IllegalAccessException { Class<? extends Configuration> implClass = Class .forName(finalClass, false, Thread.currentThread().getContextClassLoader()) .asSubclass(Configuration.class); @SuppressWarnings("deprecation") Configuration result = implClass.newInstance(); return result; } }); AccessController.doPrivileged(new PrivilegedExceptionAction<>() { public Void run() { setConfiguration(untrustedImpl); return null; } }, Objects.requireNonNull(untrustedImpl.acc)); } catch (PrivilegedActionException e) { Exception ee = e.getException(); if (ee instanceof InstantiationException) { throw (SecurityException) new SecurityException( "Configuration error:" + ee.getCause().getMessage() + "\n") .initCause(ee.getCause()); } else { throw (SecurityException) new SecurityException( "Configuration error: " + ee.toString() + "\n").initCause(ee); } } } return configuration; } } /** * Set the login {@code Configuration}. * * @param configuration the new {@code Configuration} * * @exception SecurityException if the current thread does not have * Permission to set the {@code Configuration}. * * @see #getConfiguration */ public static void setConfiguration(Configuration configuration) { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(new AuthPermission("setLoginConfiguration")); Configuration.configuration = configuration; } /** * Returns a Configuration object of the specified type. * * <p> This method traverses the list of registered security providers, * starting with the most preferred Provider. * A new Configuration object encapsulating the * ConfigurationSpi implementation from the first * Provider that supports the specified type is returned. * * <p> Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote * The JDK Reference Implementation additionally uses the * {@code jdk.security.provider.preferred} * {@link Security#getProperty(String) Security} property to determine * the preferred provider order for the specified algorithm. This * may be different than the order of providers returned by * {@link Security#getProviders() Security.getProviders()}. * * @param type the specified Configuration type. See the Configuration * section in the <a href= * "{@docRoot}/../specs/security/standard-names.html#configuration-types"> * Java Security Standard Algorithm Names Specification</a> * for a list of standard Configuration types. * * @param params parameters for the Configuration, which may be null. * * @return the new {@code Configuration} object * * @throws IllegalArgumentException if the specified parameters * are not understood by the {@code ConfigurationSpi} * implementation from the selected {@code Provider} * * @throws NoSuchAlgorithmException if no {@code Provider} supports a * {@code ConfigurationSpi} implementation for the specified type * * @throws NullPointerException if {@code type} is {@code null} * * @throws SecurityException if the caller does not have permission * to get a {@code Configuration} instance for the specified type * * @see Provider * * @since 1.6 */ public static Configuration getInstance(String type, Configuration.Parameters params) throws NoSuchAlgorithmException { Objects.requireNonNull(type, "null type name"); checkPermission(type); try { GetInstance.Instance instance = GetInstance.getInstance("Configuration", ConfigurationSpi.class, type, params); return new ConfigDelegate((ConfigurationSpi) instance.impl, instance.provider, type, params); } catch (NoSuchAlgorithmException nsae) { return handleException(nsae); } } /** * Returns a Configuration object of the specified type. * * <p> A new Configuration object encapsulating the * ConfigurationSpi implementation from the specified provider * is returned. The specified provider must be registered * in the provider list. * * <p> Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * * @param type the specified Configuration type. See the Configuration * section in the <a href= * "{@docRoot}/../specs/security/standard-names.html#configuration-types"> * Java Security Standard Algorithm Names Specification</a> * for a list of standard Configuration types. * * @param params parameters for the Configuration, which may be null. * * @param provider the provider. * * @return the new {@code Configuration} object * * @throws IllegalArgumentException if the specified provider * is {@code null} or empty, or if the specified parameters * are not understood by the {@code ConfigurationSpi} * implementation from the specified provider * * @throws NoSuchProviderException if the specified provider is not * registered in the security provider list * * @throws NoSuchAlgorithmException if the specified provider does not * support a {@code ConfigurationSpi} implementation for the * specified type * * @throws NullPointerException if {@code type} is {@code null} * * @throws SecurityException if the caller does not have permission * to get a {@code Configuration} instance for the specified type * * @see Provider * @since 1.6 */ public static Configuration getInstance(String type, Configuration.Parameters params, String provider) throws NoSuchProviderException, NoSuchAlgorithmException { Objects.requireNonNull(type, "null type name"); if (provider == null || provider.isEmpty()) { throw new IllegalArgumentException("missing provider"); } checkPermission(type); try { GetInstance.Instance instance = GetInstance.getInstance("Configuration", ConfigurationSpi.class, type, params, provider); return new ConfigDelegate((ConfigurationSpi) instance.impl, instance.provider, type, params); } catch (NoSuchAlgorithmException nsae) { return handleException(nsae); } } /** * Returns a Configuration object of the specified type. * * <p> A new Configuration object encapsulating the * ConfigurationSpi implementation from the specified Provider * object is returned. Note that the specified Provider object * does not have to be registered in the provider list. * * @param type the specified Configuration type. See the Configuration * section in the <a href= * "{@docRoot}/../specs/security/standard-names.html#configuration-types"> * Java Security Standard Algorithm Names Specification</a> * for a list of standard Configuration types. * * @param params parameters for the Configuration, which may be null. * * @param provider the Provider. * * @return the new {@code Configuration} object * * @throws IllegalArgumentException if the specified {@code Provider} * is {@code null}, or if the specified parameters are not * understood by the {@code ConfigurationSpi} implementation * from the specified Provider * * @throws NoSuchAlgorithmException if the specified {@code Provider} * does not support a {@code ConfigurationSpi} implementation * for the specified type * * @throws NullPointerException if {@code type} is {@code null} * * @throws SecurityException if the caller does not have permission * to get a {@code Configuration} instance for the specified type * * @see Provider * @since 1.6 */ public static Configuration getInstance(String type, Configuration.Parameters params, Provider provider) throws NoSuchAlgorithmException { Objects.requireNonNull(type, "null type name"); if (provider == null) { throw new IllegalArgumentException("missing provider"); } checkPermission(type); try { GetInstance.Instance instance = GetInstance.getInstance("Configuration", ConfigurationSpi.class, type, params, provider); return new ConfigDelegate((ConfigurationSpi) instance.impl, instance.provider, type, params); } catch (NoSuchAlgorithmException nsae) { return handleException(nsae); } } private static Configuration handleException(NoSuchAlgorithmException nsae) throws NoSuchAlgorithmException { Throwable cause = nsae.getCause(); if (cause instanceof IllegalArgumentException) { throw (IllegalArgumentException) cause; } throw nsae; } /** * Return the Provider of this Configuration. * * <p> This Configuration instance will only have a Provider if it * was obtained via a call to {@code Configuration.getInstance}. * Otherwise this method returns null. * * @return the Provider of this Configuration, or null. * * @since 1.6 */ public Provider getProvider() { return null; } /** * Return the type of this Configuration. * * <p> This Configuration instance will only have a type if it * was obtained via a call to {@code Configuration.getInstance}. * Otherwise this method returns null. * * @return the type of this Configuration, or null. * * @since 1.6 */ public String getType() { return null; } /** * Return Configuration parameters. * * <p> This Configuration instance will only have parameters if it * was obtained via a call to {@code Configuration.getInstance}. * Otherwise this method returns null. * * @return Configuration parameters, or null. * * @since 1.6 */ public Configuration.Parameters getParameters() { return null; } /** * Retrieve the AppConfigurationEntries for the specified {@code name} * from this Configuration. * * @param name the name used to index the Configuration. * * @return an array of AppConfigurationEntries for the specified {@code name} * from this Configuration, or null if there are no entries * for the specified {@code name} */ public abstract AppConfigurationEntry[] getAppConfigurationEntry(String name); /** * Refresh and reload the Configuration. * * <p> This method causes this Configuration object to refresh/reload its * contents in an implementation-dependent manner. * For example, if this Configuration object stores its entries in a file, * calling {@code refresh} may cause the file to be re-read. * * <p> The default implementation of this method does nothing. * This method should be overridden if a refresh operation is supported * by the implementation. * * @exception SecurityException if the caller does not have permission * to refresh its Configuration. */ public void refresh() { } /** * This subclass is returned by the getInstance calls. All Configuration * calls are delegated to the underlying ConfigurationSpi. */ private static class ConfigDelegate extends Configuration { private ConfigurationSpi spi; private Provider p; private String type; private Configuration.Parameters params; private ConfigDelegate(ConfigurationSpi spi, Provider p, String type, Configuration.Parameters params) { this.spi = spi; this.p = p; this.type = type; this.params = params; } public String getType() { return type; } public Configuration.Parameters getParameters() { return params; } public Provider getProvider() { return p; } public AppConfigurationEntry[] getAppConfigurationEntry(String name) { return spi.engineGetAppConfigurationEntry(name); } public void refresh() { spi.engineRefresh(); } } /** * This represents a marker interface for Configuration parameters. * * @since 1.6 */ public static interface Parameters { } }