Path: blob/master/src/java.base/share/classes/javax/security/auth/login/Configuration.java
67848 views
/*1* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.security.auth.login;2627import javax.security.auth.AuthPermission;2829import java.security.AccessController;30import java.security.PrivilegedAction;31import java.security.PrivilegedExceptionAction;32import java.security.PrivilegedActionException;33import java.security.NoSuchAlgorithmException;34import java.security.NoSuchProviderException;35import java.security.Provider;36import java.security.Security;37import java.util.Objects;3839import sun.security.jca.GetInstance;4041/**42* A Configuration object is responsible for specifying which LoginModules43* should be used for a particular application, and in what order the44* LoginModules should be invoked.45*46* <p> A login configuration contains the following information.47* Note that this example only represents the default syntax for the48* {@code Configuration}. Subclass implementations of this class49* may implement alternative syntaxes and may retrieve the50* {@code Configuration} from any source such as files, databases,51* or servers.52*53* <pre>54* Name {55* ModuleClass Flag ModuleOptions;56* ModuleClass Flag ModuleOptions;57* ModuleClass Flag ModuleOptions;58* };59* Name {60* ModuleClass Flag ModuleOptions;61* ModuleClass Flag ModuleOptions;62* };63* other {64* ModuleClass Flag ModuleOptions;65* ModuleClass Flag ModuleOptions;66* };67* </pre>68*69* <p> Each entry in the {@code Configuration} is indexed via an70* application name, <i>Name</i>, and contains a list of71* LoginModules configured for that application. Each {@code LoginModule}72* is specified via its fully qualified class name.73* Authentication proceeds down the module list in the exact order specified.74* If an application does not have a specific entry,75* it defaults to the specific entry for "<i>other</i>".76*77* <p> The <i>Flag</i> value controls the overall behavior as authentication78* proceeds down the stack. The following represents a description of the79* valid values for <i>Flag</i> and their respective semantics:80*81* <pre>82* 1) Required - The {@code LoginModule} is required to succeed.83* If it succeeds or fails, authentication still continues84* to proceed down the {@code LoginModule} list.85*86* 2) Requisite - The {@code LoginModule} is required to succeed.87* If it succeeds, authentication continues down the88* {@code LoginModule} list. If it fails,89* control immediately returns to the application90* (authentication does not proceed down the91* {@code LoginModule} list).92*93* 3) Sufficient - The {@code LoginModule} is not required to94* succeed. If it does succeed, control immediately95* returns to the application (authentication does not96* proceed down the {@code LoginModule} list).97* If it fails, authentication continues down the98* {@code LoginModule} list.99*100* 4) Optional - The {@code LoginModule} is not required to101* succeed. If it succeeds or fails,102* authentication still continues to proceed down the103* {@code LoginModule} list.104* </pre>105*106* <p> The overall authentication succeeds only if all <i>Required</i> and107* <i>Requisite</i> LoginModules succeed. If a <i>Sufficient</i>108* {@code LoginModule} is configured and succeeds,109* then only the <i>Required</i> and <i>Requisite</i> LoginModules prior to110* that <i>Sufficient</i> {@code LoginModule} need to have succeeded for111* the overall authentication to succeed. If no <i>Required</i> or112* <i>Requisite</i> LoginModules are configured for an application,113* then at least one <i>Sufficient</i> or <i>Optional</i>114* {@code LoginModule} must succeed.115*116* <p> <i>ModuleOptions</i> is a space separated list of117* {@code LoginModule}-specific values which are passed directly to118* the underlying LoginModules. Options are defined by the119* {@code LoginModule} itself, and control the behavior within it.120* For example, a {@code LoginModule} may define options to support121* debugging/testing capabilities. The correct way to specify options in the122* {@code Configuration} is by using the following key-value pairing:123* <i>debug="true"</i>. The key and value should be separated by an124* 'equals' symbol, and the value should be surrounded by double quotes.125* If a String in the form, ${system.property}, occurs in the value,126* it will be expanded to the value of the system property.127* Note that there is no limit to the number of128* options a {@code LoginModule} may define.129*130* <p> The following represents an example {@code Configuration} entry131* based on the syntax above:132*133* <pre>134* Login {135* com.sun.security.auth.module.UnixLoginModule required;136* com.sun.security.auth.module.Krb5LoginModule optional137* useTicketCache="true"138* ticketCache="${user.home}${/}tickets";139* };140* </pre>141*142* <p> This {@code Configuration} specifies that an application named,143* "Login", requires users to first authenticate to the144* <i>com.sun.security.auth.module.UnixLoginModule</i>, which is145* required to succeed. Even if the <i>UnixLoginModule</i>146* authentication fails, the147* <i>com.sun.security.auth.module.Krb5LoginModule</i>148* still gets invoked. This helps hide the source of failure.149* Since the <i>Krb5LoginModule</i> is <i>Optional</i>, the overall150* authentication succeeds only if the <i>UnixLoginModule</i>151* (<i>Required</i>) succeeds.152*153* <p> Also note that the LoginModule-specific options,154* <i>useTicketCache="true"</i> and155* <i>ticketCache=${user.home}${/}tickets"</i>,156* are passed to the <i>Krb5LoginModule</i>.157* These options instruct the <i>Krb5LoginModule</i> to158* use the ticket cache at the specified location.159* The system properties, <i>user.home</i> and <i>/</i>160* (file.separator), are expanded to their respective values.161*162* <p> There is only one Configuration object installed in the runtime at any163* given time. A Configuration object can be installed by calling the164* {@code setConfiguration} method. The installed Configuration object165* can be obtained by calling the {@code getConfiguration} method.166*167* <p> If no Configuration object has been installed in the runtime, a call to168* {@code getConfiguration} installs an instance of the default169* Configuration implementation (a default subclass implementation of this170* abstract class).171* The default Configuration implementation can be changed by setting the value172* of the {@code login.configuration.provider} security property to the fully173* qualified name of the desired Configuration subclass implementation.174*175* <p> Application code can directly subclass Configuration to provide a custom176* implementation. In addition, an instance of a Configuration object can be177* constructed by invoking one of the {@code getInstance} factory methods178* with a standard type. The default policy type is "JavaLoginConfig".179* See the Configuration section in the <a href=180* "{@docRoot}/../specs/security/standard-names.html#configuration-types">181* Java Security Standard Algorithm Names Specification</a>182* for a list of standard Configuration types.183*184* @since 1.4185* @see javax.security.auth.login.LoginContext186* @see java.security.Security security properties187*/188public abstract class Configuration {189190private static Configuration configuration;191192@SuppressWarnings("removal")193private final java.security.AccessControlContext acc =194java.security.AccessController.getContext();195196private static void checkPermission(String type) {197@SuppressWarnings("removal")198SecurityManager sm = System.getSecurityManager();199if (sm != null) {200sm.checkPermission(new AuthPermission201("createLoginConfiguration." + type));202}203}204205/**206* Sole constructor. (For invocation by subclass constructors, typically207* implicit.)208*/209protected Configuration() { }210211/**212* Get the installed login Configuration.213*214* @return the login Configuration. If a Configuration object was set215* via the {@code Configuration.setConfiguration} method,216* then that object is returned. Otherwise, a default217* Configuration object is returned.218*219* @exception SecurityException if the caller does not have permission220* to retrieve the Configuration.221*222* @see #setConfiguration223*/224@SuppressWarnings("removal")225public static Configuration getConfiguration() {226227SecurityManager sm = System.getSecurityManager();228if (sm != null)229sm.checkPermission(new AuthPermission("getLoginConfiguration"));230231synchronized (Configuration.class) {232if (configuration == null) {233String config_class = null;234config_class = AccessController.doPrivileged235(new PrivilegedAction<>() {236public String run() {237return java.security.Security.getProperty238("login.configuration.provider");239}240});241if (config_class == null) {242config_class = "sun.security.provider.ConfigFile";243}244245try {246final String finalClass = config_class;247Configuration untrustedImpl = AccessController.doPrivileged(248new PrivilegedExceptionAction<>() {249public Configuration run() throws ClassNotFoundException,250InstantiationException,251IllegalAccessException {252Class<? extends Configuration> implClass = Class.forName(253finalClass, false,254Thread.currentThread().getContextClassLoader()255).asSubclass(Configuration.class);256@SuppressWarnings("deprecation")257Configuration result = implClass.newInstance();258return result;259}260});261AccessController.doPrivileged(262new PrivilegedExceptionAction<>() {263public Void run() {264setConfiguration(untrustedImpl);265return null;266}267}, Objects.requireNonNull(untrustedImpl.acc)268);269} catch (PrivilegedActionException e) {270Exception ee = e.getException();271if (ee instanceof InstantiationException) {272throw (SecurityException) new273SecurityException274("Configuration error:" +275ee.getCause().getMessage() +276"\n").initCause(ee.getCause());277} else {278throw (SecurityException) new279SecurityException280("Configuration error: " +281ee.toString() +282"\n").initCause(ee);283}284}285}286return configuration;287}288}289290/**291* Set the login {@code Configuration}.292*293* @param configuration the new {@code Configuration}294*295* @exception SecurityException if the current thread does not have296* Permission to set the {@code Configuration}.297*298* @see #getConfiguration299*/300public static void setConfiguration(Configuration configuration) {301@SuppressWarnings("removal")302SecurityManager sm = System.getSecurityManager();303if (sm != null)304sm.checkPermission(new AuthPermission("setLoginConfiguration"));305Configuration.configuration = configuration;306}307308/**309* Returns a Configuration object of the specified type.310*311* <p> This method traverses the list of registered security providers,312* starting with the most preferred Provider.313* A new Configuration object encapsulating the314* ConfigurationSpi implementation from the first315* Provider that supports the specified type is returned.316*317* <p> Note that the list of registered providers may be retrieved via318* the {@link Security#getProviders() Security.getProviders()} method.319*320* @implNote321* The JDK Reference Implementation additionally uses the322* {@code jdk.security.provider.preferred}323* {@link Security#getProperty(String) Security} property to determine324* the preferred provider order for the specified algorithm. This325* may be different than the order of providers returned by326* {@link Security#getProviders() Security.getProviders()}.327*328* @param type the specified Configuration type. See the Configuration329* section in the <a href=330* "{@docRoot}/../specs/security/standard-names.html#configuration-types">331* Java Security Standard Algorithm Names Specification</a>332* for a list of standard Configuration types.333*334* @param params parameters for the Configuration, which may be null.335*336* @return the new {@code Configuration} object337*338* @throws IllegalArgumentException if the specified parameters339* are not understood by the {@code ConfigurationSpi}340* implementation from the selected {@code Provider}341*342* @throws NoSuchAlgorithmException if no {@code Provider} supports a343* {@code ConfigurationSpi} implementation for the specified type344*345* @throws NullPointerException if {@code type} is {@code null}346*347* @throws SecurityException if the caller does not have permission348* to get a {@code Configuration} instance for the specified type349*350* @see Provider351*352* @since 1.6353*/354public static Configuration getInstance(String type,355Configuration.Parameters params)356throws NoSuchAlgorithmException {357358Objects.requireNonNull(type, "null type name");359checkPermission(type);360try {361GetInstance.Instance instance = GetInstance.getInstance362("Configuration",363ConfigurationSpi.class,364type,365params);366return new ConfigDelegate((ConfigurationSpi)instance.impl,367instance.provider,368type,369params);370} catch (NoSuchAlgorithmException nsae) {371return handleException (nsae);372}373}374375/**376* Returns a Configuration object of the specified type.377*378* <p> A new Configuration object encapsulating the379* ConfigurationSpi implementation from the specified provider380* is returned. The specified provider must be registered381* in the provider list.382*383* <p> Note that the list of registered providers may be retrieved via384* the {@link Security#getProviders() Security.getProviders()} method.385*386* @param type the specified Configuration type. See the Configuration387* section in the <a href=388* "{@docRoot}/../specs/security/standard-names.html#configuration-types">389* Java Security Standard Algorithm Names Specification</a>390* for a list of standard Configuration types.391*392* @param params parameters for the Configuration, which may be null.393*394* @param provider the provider.395*396* @return the new {@code Configuration} object397*398* @throws IllegalArgumentException if the specified provider399* is {@code null} or empty, or if the specified parameters400* are not understood by the {@code ConfigurationSpi}401* implementation from the specified provider402*403* @throws NoSuchProviderException if the specified provider is not404* registered in the security provider list405*406* @throws NoSuchAlgorithmException if the specified provider does not407* support a {@code ConfigurationSpi} implementation for the408* specified type409*410* @throws NullPointerException if {@code type} is {@code null}411*412* @throws SecurityException if the caller does not have permission413* to get a {@code Configuration} instance for the specified type414*415* @see Provider416* @since 1.6417*/418public static Configuration getInstance(String type,419Configuration.Parameters params,420String provider)421throws NoSuchProviderException, NoSuchAlgorithmException {422423Objects.requireNonNull(type, "null type name");424if (provider == null || provider.isEmpty()) {425throw new IllegalArgumentException("missing provider");426}427428checkPermission(type);429try {430GetInstance.Instance instance = GetInstance.getInstance431("Configuration",432ConfigurationSpi.class,433type,434params,435provider);436return new ConfigDelegate((ConfigurationSpi)instance.impl,437instance.provider,438type,439params);440} catch (NoSuchAlgorithmException nsae) {441return handleException (nsae);442}443}444445/**446* Returns a Configuration object of the specified type.447*448* <p> A new Configuration object encapsulating the449* ConfigurationSpi implementation from the specified Provider450* object is returned. Note that the specified Provider object451* does not have to be registered in the provider list.452*453* @param type the specified Configuration type. See the Configuration454* section in the <a href=455* "{@docRoot}/../specs/security/standard-names.html#configuration-types">456* Java Security Standard Algorithm Names Specification</a>457* for a list of standard Configuration types.458*459* @param params parameters for the Configuration, which may be null.460*461* @param provider the Provider.462*463* @return the new {@code Configuration} object464*465* @throws IllegalArgumentException if the specified {@code Provider}466* is {@code null}, or if the specified parameters are not467* understood by the {@code ConfigurationSpi} implementation468* from the specified Provider469*470* @throws NoSuchAlgorithmException if the specified {@code Provider}471* does not support a {@code ConfigurationSpi} implementation472* for the specified type473*474* @throws NullPointerException if {@code type} is {@code null}475*476* @throws SecurityException if the caller does not have permission477* to get a {@code Configuration} instance for the specified type478*479* @see Provider480* @since 1.6481*/482public static Configuration getInstance(String type,483Configuration.Parameters params,484Provider provider)485throws NoSuchAlgorithmException {486487Objects.requireNonNull(type, "null type name");488if (provider == null) {489throw new IllegalArgumentException("missing provider");490}491492checkPermission(type);493try {494GetInstance.Instance instance = GetInstance.getInstance495("Configuration",496ConfigurationSpi.class,497type,498params,499provider);500return new ConfigDelegate((ConfigurationSpi)instance.impl,501instance.provider,502type,503params);504} catch (NoSuchAlgorithmException nsae) {505return handleException (nsae);506}507}508509private static Configuration handleException(NoSuchAlgorithmException nsae)510throws NoSuchAlgorithmException {511Throwable cause = nsae.getCause();512if (cause instanceof IllegalArgumentException) {513throw (IllegalArgumentException)cause;514}515throw nsae;516}517518/**519* Return the Provider of this Configuration.520*521* <p> This Configuration instance will only have a Provider if it522* was obtained via a call to {@code Configuration.getInstance}.523* Otherwise this method returns null.524*525* @return the Provider of this Configuration, or null.526*527* @since 1.6528*/529public Provider getProvider() {530return null;531}532533/**534* Return the type of this Configuration.535*536* <p> This Configuration instance will only have a type if it537* was obtained via a call to {@code Configuration.getInstance}.538* Otherwise this method returns null.539*540* @return the type of this Configuration, or null.541*542* @since 1.6543*/544public String getType() {545return null;546}547548/**549* Return Configuration parameters.550*551* <p> This Configuration instance will only have parameters if it552* was obtained via a call to {@code Configuration.getInstance}.553* Otherwise this method returns null.554*555* @return Configuration parameters, or null.556*557* @since 1.6558*/559public Configuration.Parameters getParameters() {560return null;561}562563/**564* Retrieve the AppConfigurationEntries for the specified {@code name}565* from this Configuration.566*567* @param name the name used to index the Configuration.568*569* @return an array of AppConfigurationEntries for the specified {@code name}570* from this Configuration, or null if there are no entries571* for the specified {@code name}572*/573public abstract AppConfigurationEntry[] getAppConfigurationEntry574(String name);575576/**577* Refresh and reload the Configuration.578*579* <p> This method causes this Configuration object to refresh/reload its580* contents in an implementation-dependent manner.581* For example, if this Configuration object stores its entries in a file,582* calling {@code refresh} may cause the file to be re-read.583*584* <p> The default implementation of this method does nothing.585* This method should be overridden if a refresh operation is supported586* by the implementation.587*588* @exception SecurityException if the caller does not have permission589* to refresh its Configuration.590*/591public void refresh() { }592593/**594* This subclass is returned by the getInstance calls. All Configuration595* calls are delegated to the underlying ConfigurationSpi.596*/597private static class ConfigDelegate extends Configuration {598599private ConfigurationSpi spi;600private Provider p;601private String type;602private Configuration.Parameters params;603604private ConfigDelegate(ConfigurationSpi spi, Provider p,605String type, Configuration.Parameters params) {606this.spi = spi;607this.p = p;608this.type = type;609this.params = params;610}611612public String getType() { return type; }613614public Configuration.Parameters getParameters() { return params; }615616public Provider getProvider() { return p; }617618public AppConfigurationEntry[] getAppConfigurationEntry(String name) {619return spi.engineGetAppConfigurationEntry(name);620}621622public void refresh() {623spi.engineRefresh();624}625}626627/**628* This represents a marker interface for Configuration parameters.629*630* @since 1.6631*/632public static interface Parameters { }633}634635636