8016848: javax_security/auth/login tests fail in compact 1 and 2 profiles
Change the default value of the "login.configuration.provider" security property to sun.security.provider.ConfigFile Reviewed-by: xuelei
This commit is contained in:
parent
1cf74954ed
commit
bb0b967894
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,9 +30,9 @@ import javax.security.auth.login.Configuration;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
// NOTE: As of JDK 8, this class instantiates
|
// NOTE: As of JDK 8, this class instantiates
|
||||||
// sun.security.provider.ConfigSpiFile and forwards all methods to that
|
// sun.security.provider.ConfigFile.Spi and forwards all methods to that
|
||||||
// implementation. All implementation fixes and enhancements should be made to
|
// implementation. All implementation fixes and enhancements should be made to
|
||||||
// sun.security.provider.ConfigSpiFile and not this class.
|
// sun.security.provider.ConfigFile.Spi and not this class.
|
||||||
// See JDK-8005117 for more information.
|
// See JDK-8005117 for more information.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,7 +85,7 @@ import java.net.URI;
|
|||||||
*/
|
*/
|
||||||
public class ConfigFile extends Configuration {
|
public class ConfigFile extends Configuration {
|
||||||
|
|
||||||
private sun.security.provider.ConfigSpiFile configFile;
|
private final sun.security.provider.ConfigFile.Spi spi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@code Configuration} object.
|
* Create a new {@code Configuration} object.
|
||||||
@ -94,7 +94,7 @@ public class ConfigFile extends Configuration {
|
|||||||
* initialized
|
* initialized
|
||||||
*/
|
*/
|
||||||
public ConfigFile() {
|
public ConfigFile() {
|
||||||
configFile = new sun.security.provider.ConfigSpiFile();
|
spi = new sun.security.provider.ConfigFile.Spi();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,7 +106,7 @@ public class ConfigFile extends Configuration {
|
|||||||
* @throws NullPointerException if {@code uri} is null
|
* @throws NullPointerException if {@code uri} is null
|
||||||
*/
|
*/
|
||||||
public ConfigFile(URI uri) {
|
public ConfigFile(URI uri) {
|
||||||
configFile = new sun.security.provider.ConfigSpiFile(uri);
|
spi = new sun.security.provider.ConfigFile.Spi(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,7 +123,7 @@ public class ConfigFile extends Configuration {
|
|||||||
public AppConfigurationEntry[] getAppConfigurationEntry
|
public AppConfigurationEntry[] getAppConfigurationEntry
|
||||||
(String applicationName) {
|
(String applicationName) {
|
||||||
|
|
||||||
return configFile.engineGetAppConfigurationEntry(applicationName);
|
return spi.engineGetAppConfigurationEntry(applicationName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,7 +134,7 @@ public class ConfigFile extends Configuration {
|
|||||||
* to refresh the {@code Configuration}
|
* to refresh the {@code Configuration}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void refresh() {
|
public void refresh() {
|
||||||
configFile.engineRefresh();
|
spi.engineRefresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ import sun.security.jca.GetInstance;
|
|||||||
* LoginModules configured for that application. Each {@code LoginModule}
|
* LoginModules configured for that application. Each {@code LoginModule}
|
||||||
* is specified via its fully qualified class name.
|
* is specified via its fully qualified class name.
|
||||||
* Authentication proceeds down the module list in the exact order specified.
|
* Authentication proceeds down the module list in the exact order specified.
|
||||||
* If an application does not have specific entry,
|
* If an application does not have a specific entry,
|
||||||
* it defaults to the specific entry for "<i>other</i>".
|
* it defaults to the specific entry for "<i>other</i>".
|
||||||
*
|
*
|
||||||
* <p> The <i>Flag</i> value controls the overall behavior as authentication
|
* <p> The <i>Flag</i> value controls the overall behavior as authentication
|
||||||
@ -248,7 +248,7 @@ public abstract class Configuration {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (config_class == null) {
|
if (config_class == null) {
|
||||||
config_class = "com.sun.security.auth.login.ConfigFile";
|
config_class = "sun.security.provider.ConfigFile";
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
669
jdk/src/share/classes/sun/security/provider/ConfigFile.java
Normal file
669
jdk/src/share/classes/sun/security/provider/ConfigFile.java
Normal file
@ -0,0 +1,669 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000, 2013, 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 sun.security.provider;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import java.security.PrivilegedActionException;
|
||||||
|
import java.security.PrivilegedExceptionAction;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.security.URIParameter;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import javax.security.auth.AuthPermission;
|
||||||
|
import javax.security.auth.login.AppConfigurationEntry;
|
||||||
|
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
|
||||||
|
import javax.security.auth.login.Configuration;
|
||||||
|
import javax.security.auth.login.ConfigurationSpi;
|
||||||
|
import sun.security.util.Debug;
|
||||||
|
import sun.security.util.PropertyExpander;
|
||||||
|
import sun.security.util.ResourcesMgr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a default implementation for
|
||||||
|
* {@code javax.security.auth.login.Configuration}.
|
||||||
|
*
|
||||||
|
* <p> This object stores the runtime login configuration representation,
|
||||||
|
* and is the amalgamation of multiple static login configurations that
|
||||||
|
* resides in files. The algorithm for locating the login configuration
|
||||||
|
* file(s) and reading their information into this {@code Configuration}
|
||||||
|
* object is:
|
||||||
|
*
|
||||||
|
* <ol>
|
||||||
|
* <li>
|
||||||
|
* Loop through the security properties,
|
||||||
|
* <i>login.config.url.1</i>, <i>login.config.url.2</i>, ...,
|
||||||
|
* <i>login.config.url.X</i>.
|
||||||
|
* Each property value specifies a {@code URL} pointing to a
|
||||||
|
* login configuration file to be loaded. Read in and load
|
||||||
|
* each configuration.
|
||||||
|
*
|
||||||
|
* <li>
|
||||||
|
* The {@code java.lang.System} property
|
||||||
|
* <i>java.security.auth.login.config</i>
|
||||||
|
* may also be set to a {@code URL} pointing to another
|
||||||
|
* login configuration file
|
||||||
|
* (which is the case when a user uses the -D switch at runtime).
|
||||||
|
* If this property is defined, and its use is allowed by the
|
||||||
|
* security property file (the Security property,
|
||||||
|
* <i>policy.allowSystemProperty</i> is set to <i>true</i>),
|
||||||
|
* also load that login configuration.
|
||||||
|
*
|
||||||
|
* <li>
|
||||||
|
* If the <i>java.security.auth.login.config</i> property is defined using
|
||||||
|
* "==" (rather than "="), then ignore all other specified
|
||||||
|
* login configurations and only load this configuration.
|
||||||
|
*
|
||||||
|
* <li>
|
||||||
|
* If no system or security properties were set, try to read from the file,
|
||||||
|
* ${user.home}/.java.login.config, where ${user.home} is the value
|
||||||
|
* represented by the "user.home" System property.
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p> The configuration syntax supported by this implementation
|
||||||
|
* is exactly that syntax specified in the
|
||||||
|
* {@code javax.security.auth.login.Configuration} class.
|
||||||
|
*
|
||||||
|
* @see javax.security.auth.login.LoginContext
|
||||||
|
* @see java.security.Security security properties
|
||||||
|
*/
|
||||||
|
public final class ConfigFile extends Configuration {
|
||||||
|
|
||||||
|
private final Spi spi;
|
||||||
|
|
||||||
|
public ConfigFile() {
|
||||||
|
spi = new Spi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AppConfigurationEntry[] getAppConfigurationEntry(String appName) {
|
||||||
|
return spi.engineGetAppConfigurationEntry(appName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void refresh() {
|
||||||
|
spi.engineRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class Spi extends ConfigurationSpi {
|
||||||
|
|
||||||
|
private URL url;
|
||||||
|
private boolean expandProp = true;
|
||||||
|
private Map<String, List<AppConfigurationEntry>> configuration;
|
||||||
|
private int linenum;
|
||||||
|
private StreamTokenizer st;
|
||||||
|
private int lookahead;
|
||||||
|
|
||||||
|
private static Debug debugConfig = Debug.getInstance("configfile");
|
||||||
|
private static Debug debugParser = Debug.getInstance("configparser");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@code ConfigurationSpi} object.
|
||||||
|
*
|
||||||
|
* @throws SecurityException if the {@code ConfigurationSpi} can not be
|
||||||
|
* initialized
|
||||||
|
*/
|
||||||
|
public Spi() {
|
||||||
|
try {
|
||||||
|
init();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new SecurityException(ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@code ConfigurationSpi} object from the specified
|
||||||
|
* {@code URI}.
|
||||||
|
*
|
||||||
|
* @param uri the {@code URI}
|
||||||
|
* @throws SecurityException if the {@code ConfigurationSpi} can not be
|
||||||
|
* initialized
|
||||||
|
* @throws NullPointerException if {@code uri} is null
|
||||||
|
*/
|
||||||
|
public Spi(URI uri) {
|
||||||
|
// only load config from the specified URI
|
||||||
|
try {
|
||||||
|
url = uri.toURL();
|
||||||
|
init();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new SecurityException(ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Spi(final Configuration.Parameters params) throws IOException {
|
||||||
|
|
||||||
|
// call in a doPrivileged
|
||||||
|
//
|
||||||
|
// we have already passed the Configuration.getInstance
|
||||||
|
// security check. also this class is not freely accessible
|
||||||
|
// (it is in the "sun" package).
|
||||||
|
|
||||||
|
try {
|
||||||
|
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||||
|
public Void run() throws IOException {
|
||||||
|
if (params == null) {
|
||||||
|
init();
|
||||||
|
} else {
|
||||||
|
if (!(params instanceof URIParameter)) {
|
||||||
|
throw new IllegalArgumentException
|
||||||
|
("Unrecognized parameter: " + params);
|
||||||
|
}
|
||||||
|
URIParameter uriParam = (URIParameter)params;
|
||||||
|
url = uriParam.getURI().toURL();
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (PrivilegedActionException pae) {
|
||||||
|
throw (IOException)pae.getException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if init() throws some other RuntimeException,
|
||||||
|
// let it percolate up naturally.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read and initialize the entire login Configuration from the
|
||||||
|
* configured URL.
|
||||||
|
*
|
||||||
|
* @throws IOException if the Configuration can not be initialized
|
||||||
|
* @throws SecurityException if the caller does not have permission
|
||||||
|
* to initialize the Configuration
|
||||||
|
*/
|
||||||
|
private void init() throws IOException {
|
||||||
|
|
||||||
|
boolean initialized = false;
|
||||||
|
|
||||||
|
// For policy.expandProperties, check if either a security or system
|
||||||
|
// property is set to false (old code erroneously checked the system
|
||||||
|
// prop so we must check both to preserve compatibility).
|
||||||
|
String expand = Security.getProperty("policy.expandProperties");
|
||||||
|
if (expand == null) {
|
||||||
|
expand = System.getProperty("policy.expandProperties");
|
||||||
|
}
|
||||||
|
if ("false".equals(expand)) {
|
||||||
|
expandProp = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// new configuration
|
||||||
|
Map<String, List<AppConfigurationEntry>> newConfig = new HashMap<>();
|
||||||
|
|
||||||
|
if (url != null) {
|
||||||
|
/**
|
||||||
|
* If the caller specified a URI via Configuration.getInstance,
|
||||||
|
* we only read from that URI
|
||||||
|
*/
|
||||||
|
if (debugConfig != null) {
|
||||||
|
debugConfig.println("reading " + url);
|
||||||
|
}
|
||||||
|
init(url, newConfig);
|
||||||
|
configuration = newConfig;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caller did not specify URI via Configuration.getInstance.
|
||||||
|
* Read from URLs listed in the java.security properties file.
|
||||||
|
*/
|
||||||
|
String allowSys = Security.getProperty("policy.allowSystemProperty");
|
||||||
|
|
||||||
|
if ("true".equalsIgnoreCase(allowSys)) {
|
||||||
|
String extra_config = System.getProperty
|
||||||
|
("java.security.auth.login.config");
|
||||||
|
if (extra_config != null) {
|
||||||
|
boolean overrideAll = false;
|
||||||
|
if (extra_config.startsWith("=")) {
|
||||||
|
overrideAll = true;
|
||||||
|
extra_config = extra_config.substring(1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
extra_config = PropertyExpander.expand(extra_config);
|
||||||
|
} catch (PropertyExpander.ExpandException peee) {
|
||||||
|
throw ioException("Unable.to.properly.expand.config",
|
||||||
|
extra_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
URL configURL = null;
|
||||||
|
try {
|
||||||
|
configURL = new URL(extra_config);
|
||||||
|
} catch (MalformedURLException mue) {
|
||||||
|
File configFile = new File(extra_config);
|
||||||
|
if (configFile.exists()) {
|
||||||
|
configURL = configFile.toURI().toURL();
|
||||||
|
} else {
|
||||||
|
throw ioException(
|
||||||
|
"extra.config.No.such.file.or.directory.",
|
||||||
|
extra_config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debugConfig != null) {
|
||||||
|
debugConfig.println("reading "+configURL);
|
||||||
|
}
|
||||||
|
init(configURL, newConfig);
|
||||||
|
initialized = true;
|
||||||
|
if (overrideAll) {
|
||||||
|
if (debugConfig != null) {
|
||||||
|
debugConfig.println("overriding other policies!");
|
||||||
|
}
|
||||||
|
configuration = newConfig;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = 1;
|
||||||
|
String config_url;
|
||||||
|
while ((config_url = Security.getProperty
|
||||||
|
("login.config.url."+n)) != null) {
|
||||||
|
try {
|
||||||
|
config_url = PropertyExpander.expand
|
||||||
|
(config_url).replace(File.separatorChar, '/');
|
||||||
|
if (debugConfig != null) {
|
||||||
|
debugConfig.println("\tReading config: " + config_url);
|
||||||
|
}
|
||||||
|
init(new URL(config_url), newConfig);
|
||||||
|
initialized = true;
|
||||||
|
} catch (PropertyExpander.ExpandException peee) {
|
||||||
|
throw ioException("Unable.to.properly.expand.config",
|
||||||
|
config_url);
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialized == false && n == 1 && config_url == null) {
|
||||||
|
|
||||||
|
// get the config from the user's home directory
|
||||||
|
if (debugConfig != null) {
|
||||||
|
debugConfig.println("\tReading Policy " +
|
||||||
|
"from ~/.java.login.config");
|
||||||
|
}
|
||||||
|
config_url = System.getProperty("user.home");
|
||||||
|
String userConfigFile = config_url + File.separatorChar +
|
||||||
|
".java.login.config";
|
||||||
|
|
||||||
|
// No longer throws an exception when there's no config file
|
||||||
|
// at all. Returns an empty Configuration instead.
|
||||||
|
if (new File(userConfigFile).exists()) {
|
||||||
|
init(new File(userConfigFile).toURI().toURL(), newConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration = newConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(URL config,
|
||||||
|
Map<String, List<AppConfigurationEntry>> newConfig)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
try (InputStreamReader isr
|
||||||
|
= new InputStreamReader(getInputStream(config), "UTF-8")) {
|
||||||
|
readConfig(isr, newConfig);
|
||||||
|
} catch (FileNotFoundException fnfe) {
|
||||||
|
if (debugConfig != null) {
|
||||||
|
debugConfig.println(fnfe.toString());
|
||||||
|
}
|
||||||
|
throw new IOException(ResourcesMgr.getString
|
||||||
|
("Configuration.Error.No.such.file.or.directory",
|
||||||
|
"sun.security.util.AuthResources"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an entry from the Configuration using an application name
|
||||||
|
* as an index.
|
||||||
|
*
|
||||||
|
* @param applicationName the name used to index the Configuration.
|
||||||
|
* @return an array of AppConfigurationEntries which correspond to
|
||||||
|
* the stacked configuration of LoginModules for this
|
||||||
|
* application, or null if this application has no configured
|
||||||
|
* LoginModules.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AppConfigurationEntry[] engineGetAppConfigurationEntry
|
||||||
|
(String applicationName) {
|
||||||
|
|
||||||
|
List<AppConfigurationEntry> list = null;
|
||||||
|
synchronized (configuration) {
|
||||||
|
list = configuration.get(applicationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list == null || list.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppConfigurationEntry[] entries =
|
||||||
|
new AppConfigurationEntry[list.size()];
|
||||||
|
Iterator<AppConfigurationEntry> iterator = list.iterator();
|
||||||
|
for (int i = 0; iterator.hasNext(); i++) {
|
||||||
|
AppConfigurationEntry e = iterator.next();
|
||||||
|
entries[i] = new AppConfigurationEntry(e.getLoginModuleName(),
|
||||||
|
e.getControlFlag(),
|
||||||
|
e.getOptions());
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh and reload the Configuration by re-reading all of the
|
||||||
|
* login configurations.
|
||||||
|
*
|
||||||
|
* @throws SecurityException if the caller does not have permission
|
||||||
|
* to refresh the Configuration.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized void engineRefresh() {
|
||||||
|
|
||||||
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
if (sm != null) {
|
||||||
|
sm.checkPermission(
|
||||||
|
new AuthPermission("refreshLoginConfiguration"));
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||||
|
public Void run() {
|
||||||
|
try {
|
||||||
|
init();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new SecurityException(ioe.getLocalizedMessage(),
|
||||||
|
ioe);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readConfig(Reader reader,
|
||||||
|
Map<String, List<AppConfigurationEntry>> newConfig)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
linenum = 1;
|
||||||
|
|
||||||
|
if (!(reader instanceof BufferedReader)) {
|
||||||
|
reader = new BufferedReader(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
st = new StreamTokenizer(reader);
|
||||||
|
st.quoteChar('"');
|
||||||
|
st.wordChars('$', '$');
|
||||||
|
st.wordChars('_', '_');
|
||||||
|
st.wordChars('-', '-');
|
||||||
|
st.wordChars('*', '*');
|
||||||
|
st.lowerCaseMode(false);
|
||||||
|
st.slashSlashComments(true);
|
||||||
|
st.slashStarComments(true);
|
||||||
|
st.eolIsSignificant(true);
|
||||||
|
|
||||||
|
lookahead = nextToken();
|
||||||
|
while (lookahead != StreamTokenizer.TT_EOF) {
|
||||||
|
parseLoginEntry(newConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseLoginEntry(
|
||||||
|
Map<String, List<AppConfigurationEntry>> newConfig)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
List<AppConfigurationEntry> configEntries = new LinkedList<>();
|
||||||
|
|
||||||
|
// application name
|
||||||
|
String appName = st.sval;
|
||||||
|
lookahead = nextToken();
|
||||||
|
|
||||||
|
if (debugParser != null) {
|
||||||
|
debugParser.println("\tReading next config entry: " + appName);
|
||||||
|
}
|
||||||
|
|
||||||
|
match("{");
|
||||||
|
|
||||||
|
// get the modules
|
||||||
|
while (peek("}") == false) {
|
||||||
|
// get the module class name
|
||||||
|
String moduleClass = match("module class name");
|
||||||
|
|
||||||
|
// controlFlag (required, optional, etc)
|
||||||
|
LoginModuleControlFlag controlFlag;
|
||||||
|
String sflag = match("controlFlag").toUpperCase();
|
||||||
|
switch (sflag) {
|
||||||
|
case "REQUIRED":
|
||||||
|
controlFlag = LoginModuleControlFlag.REQUIRED;
|
||||||
|
break;
|
||||||
|
case "REQUISITE":
|
||||||
|
controlFlag = LoginModuleControlFlag.REQUISITE;
|
||||||
|
break;
|
||||||
|
case "SUFFICIENT":
|
||||||
|
controlFlag = LoginModuleControlFlag.SUFFICIENT;
|
||||||
|
break;
|
||||||
|
case "OPTIONAL":
|
||||||
|
controlFlag = LoginModuleControlFlag.OPTIONAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw ioException(
|
||||||
|
"Configuration.Error.Invalid.control.flag.flag",
|
||||||
|
sflag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the args
|
||||||
|
Map<String, String> options = new HashMap<>();
|
||||||
|
while (peek(";") == false) {
|
||||||
|
String key = match("option key");
|
||||||
|
match("=");
|
||||||
|
try {
|
||||||
|
options.put(key, expand(match("option value")));
|
||||||
|
} catch (PropertyExpander.ExpandException peee) {
|
||||||
|
throw new IOException(peee.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lookahead = nextToken();
|
||||||
|
|
||||||
|
// create the new element
|
||||||
|
if (debugParser != null) {
|
||||||
|
debugParser.println("\t\t" + moduleClass + ", " + sflag);
|
||||||
|
for (String key : options.keySet()) {
|
||||||
|
debugParser.println("\t\t\t" + key +
|
||||||
|
"=" + options.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configEntries.add(new AppConfigurationEntry(moduleClass,
|
||||||
|
controlFlag,
|
||||||
|
options));
|
||||||
|
}
|
||||||
|
|
||||||
|
match("}");
|
||||||
|
match(";");
|
||||||
|
|
||||||
|
// add this configuration entry
|
||||||
|
if (newConfig.containsKey(appName)) {
|
||||||
|
throw ioException(
|
||||||
|
"Configuration.Error.Can.not.specify.multiple.entries.for.appName",
|
||||||
|
appName);
|
||||||
|
}
|
||||||
|
newConfig.put(appName, configEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String match(String expect) throws IOException {
|
||||||
|
|
||||||
|
String value = null;
|
||||||
|
|
||||||
|
switch(lookahead) {
|
||||||
|
case StreamTokenizer.TT_EOF:
|
||||||
|
throw ioException(
|
||||||
|
"Configuration.Error.expected.expect.read.end.of.file.",
|
||||||
|
expect);
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
case StreamTokenizer.TT_WORD:
|
||||||
|
if (expect.equalsIgnoreCase("module class name") ||
|
||||||
|
expect.equalsIgnoreCase("controlFlag") ||
|
||||||
|
expect.equalsIgnoreCase("option key") ||
|
||||||
|
expect.equalsIgnoreCase("option value")) {
|
||||||
|
value = st.sval;
|
||||||
|
lookahead = nextToken();
|
||||||
|
} else {
|
||||||
|
throw ioException(
|
||||||
|
"Configuration.Error.Line.line.expected.expect.found.value.",
|
||||||
|
new Integer(linenum), expect, st.sval);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
if (expect.equalsIgnoreCase("{")) {
|
||||||
|
lookahead = nextToken();
|
||||||
|
} else {
|
||||||
|
throw ioException(
|
||||||
|
"Configuration.Error.Line.line.expected.expect.",
|
||||||
|
new Integer(linenum), expect, st.sval);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ';':
|
||||||
|
if (expect.equalsIgnoreCase(";")) {
|
||||||
|
lookahead = nextToken();
|
||||||
|
} else {
|
||||||
|
throw ioException(
|
||||||
|
"Configuration.Error.Line.line.expected.expect.",
|
||||||
|
new Integer(linenum), expect, st.sval);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '}':
|
||||||
|
if (expect.equalsIgnoreCase("}")) {
|
||||||
|
lookahead = nextToken();
|
||||||
|
} else {
|
||||||
|
throw ioException(
|
||||||
|
"Configuration.Error.Line.line.expected.expect.",
|
||||||
|
new Integer(linenum), expect, st.sval);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '=':
|
||||||
|
if (expect.equalsIgnoreCase("=")) {
|
||||||
|
lookahead = nextToken();
|
||||||
|
} else {
|
||||||
|
throw ioException(
|
||||||
|
"Configuration.Error.Line.line.expected.expect.",
|
||||||
|
new Integer(linenum), expect, st.sval);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw ioException(
|
||||||
|
"Configuration.Error.Line.line.expected.expect.found.value.",
|
||||||
|
new Integer(linenum), expect, st.sval);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean peek(String expect) {
|
||||||
|
switch (lookahead) {
|
||||||
|
case ',':
|
||||||
|
return expect.equalsIgnoreCase(",");
|
||||||
|
case ';':
|
||||||
|
return expect.equalsIgnoreCase(";");
|
||||||
|
case '{':
|
||||||
|
return expect.equalsIgnoreCase("{");
|
||||||
|
case '}':
|
||||||
|
return expect.equalsIgnoreCase("}");
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int nextToken() throws IOException {
|
||||||
|
int tok;
|
||||||
|
while ((tok = st.nextToken()) == StreamTokenizer.TT_EOL) {
|
||||||
|
linenum++;
|
||||||
|
}
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(URL url) throws IOException {
|
||||||
|
if ("file".equalsIgnoreCase(url.getProtocol())) {
|
||||||
|
// Compatibility notes:
|
||||||
|
//
|
||||||
|
// Code changed from
|
||||||
|
// String path = url.getFile().replace('/', File.separatorChar);
|
||||||
|
// return new FileInputStream(path);
|
||||||
|
//
|
||||||
|
// The original implementation would search for "/tmp/a%20b"
|
||||||
|
// when url is "file:///tmp/a%20b". This is incorrect. The
|
||||||
|
// current codes fix this bug and searches for "/tmp/a b".
|
||||||
|
// For compatibility reasons, when the file "/tmp/a b" does
|
||||||
|
// not exist, the file named "/tmp/a%20b" will be tried.
|
||||||
|
//
|
||||||
|
// This also means that if both file exists, the behavior of
|
||||||
|
// this method is changed, and the current codes choose the
|
||||||
|
// correct one.
|
||||||
|
try {
|
||||||
|
return url.openStream();
|
||||||
|
} catch (Exception e) {
|
||||||
|
String file = url.getPath();
|
||||||
|
if (url.getHost().length() > 0) { // For Windows UNC
|
||||||
|
file = "//" + url.getHost() + file;
|
||||||
|
}
|
||||||
|
if (debugConfig != null) {
|
||||||
|
debugConfig.println("cannot read " + url +
|
||||||
|
", try " + file);
|
||||||
|
}
|
||||||
|
return new FileInputStream(file);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return url.openStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String expand(String value)
|
||||||
|
throws PropertyExpander.ExpandException, IOException {
|
||||||
|
|
||||||
|
if (value.isEmpty()) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expandProp) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
String s = PropertyExpander.expand(value);
|
||||||
|
if (s == null || s.length() == 0) {
|
||||||
|
throw ioException(
|
||||||
|
"Configuration.Error.Line.line.system.property.value.expanded.to.empty.value",
|
||||||
|
new Integer(linenum), value);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IOException ioException(String resourceKey, Object... args) {
|
||||||
|
MessageFormat form = new MessageFormat(ResourcesMgr.getString
|
||||||
|
(resourceKey, "sun.security.util.AuthResources"));
|
||||||
|
return new IOException(form.format(args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,693 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2000, 2012, 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 sun.security.provider;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.security.PrivilegedActionException;
|
|
||||||
import java.security.PrivilegedExceptionAction;
|
|
||||||
import java.security.Security;
|
|
||||||
import java.security.URIParameter;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.security.auth.AuthPermission;
|
|
||||||
import javax.security.auth.login.AppConfigurationEntry;
|
|
||||||
import javax.security.auth.login.Configuration;
|
|
||||||
import javax.security.auth.login.ConfigurationSpi;
|
|
||||||
import sun.security.util.Debug;
|
|
||||||
import sun.security.util.PropertyExpander;
|
|
||||||
import sun.security.util.ResourcesMgr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents a default implementation for
|
|
||||||
* {@code javax.security.auth.login.Configuration}.
|
|
||||||
*
|
|
||||||
* <p> This object stores the runtime login configuration representation,
|
|
||||||
* and is the amalgamation of multiple static login
|
|
||||||
* configurations that resides in files.
|
|
||||||
* The algorithm for locating the login configuration file(s) and reading their
|
|
||||||
* information into this {@code Configuration} object is:
|
|
||||||
*
|
|
||||||
* <ol>
|
|
||||||
* <li>
|
|
||||||
* Loop through the security properties,
|
|
||||||
* <i>login.config.url.1</i>, <i>login.config.url.2</i>, ...,
|
|
||||||
* <i>login.config.url.X</i>.
|
|
||||||
* Each property value specifies a <code>URL</code> pointing to a
|
|
||||||
* login configuration file to be loaded. Read in and load
|
|
||||||
* each configuration.
|
|
||||||
*
|
|
||||||
* <li>
|
|
||||||
* The {@code java.lang.System} property
|
|
||||||
* <i>java.security.auth.login.config</i>
|
|
||||||
* may also be set to a {@code URL} pointing to another
|
|
||||||
* login configuration file
|
|
||||||
* (which is the case when a user uses the -D switch at runtime).
|
|
||||||
* If this property is defined, and its use is allowed by the
|
|
||||||
* security property file (the Security property,
|
|
||||||
* <i>policy.allowSystemProperty</i> is set to <i>true</i>),
|
|
||||||
* also load that login configuration.
|
|
||||||
*
|
|
||||||
* <li>
|
|
||||||
* If the <i>java.security.auth.login.config</i> property is defined using
|
|
||||||
* "==" (rather than "="), then ignore all other specified
|
|
||||||
* login configurations and only load this configuration.
|
|
||||||
*
|
|
||||||
* <li>
|
|
||||||
* If no system or security properties were set, try to read from the file,
|
|
||||||
* ${user.home}/.java.login.config, where ${user.home} is the value
|
|
||||||
* represented by the "user.home" System property.
|
|
||||||
* </ol>
|
|
||||||
*
|
|
||||||
* <p> The configuration syntax supported by this implementation
|
|
||||||
* is exactly that syntax specified in the
|
|
||||||
* {@code javax.security.auth.login.Configuration} class.
|
|
||||||
*
|
|
||||||
* @see javax.security.auth.login.LoginContext
|
|
||||||
* @see java.security.Security security properties
|
|
||||||
*/
|
|
||||||
public final class ConfigSpiFile extends ConfigurationSpi {
|
|
||||||
|
|
||||||
private URL url;
|
|
||||||
private boolean expandProp = true;
|
|
||||||
private Map<String, List<AppConfigurationEntry>> configuration;
|
|
||||||
private int linenum;
|
|
||||||
private StreamTokenizer st;
|
|
||||||
private int lookahead;
|
|
||||||
|
|
||||||
private static Debug debugConfig = Debug.getInstance("configfile");
|
|
||||||
private static Debug debugParser = Debug.getInstance("configparser");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@code Configuration} object.
|
|
||||||
*
|
|
||||||
* @throws SecurityException if the {@code Configuration} can not be
|
|
||||||
* initialized
|
|
||||||
*/
|
|
||||||
public ConfigSpiFile() {
|
|
||||||
try {
|
|
||||||
init();
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
throw new SecurityException(ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@code Configuration} object from the specified {@code URI}.
|
|
||||||
*
|
|
||||||
* @param uri the {@code URI}
|
|
||||||
* @throws SecurityException if the {@code Configuration} can not be
|
|
||||||
* initialized
|
|
||||||
* @throws NullPointerException if {@code uri} is null
|
|
||||||
*/
|
|
||||||
public ConfigSpiFile(URI uri) {
|
|
||||||
// only load config from the specified URI
|
|
||||||
try {
|
|
||||||
url = uri.toURL();
|
|
||||||
init();
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
throw new SecurityException(ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConfigSpiFile(final Configuration.Parameters params)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
// call in a doPrivileged
|
|
||||||
//
|
|
||||||
// we have already passed the Configuration.getInstance
|
|
||||||
// security check. also this class is not freely accessible
|
|
||||||
// (it is in the "sun" package).
|
|
||||||
|
|
||||||
try {
|
|
||||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
|
||||||
public Void run() throws IOException {
|
|
||||||
if (params == null) {
|
|
||||||
init();
|
|
||||||
} else {
|
|
||||||
if (!(params instanceof URIParameter)) {
|
|
||||||
throw new IllegalArgumentException
|
|
||||||
("Unrecognized parameter: " + params);
|
|
||||||
}
|
|
||||||
URIParameter uriParam = (URIParameter)params;
|
|
||||||
url = uriParam.getURI().toURL();
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (PrivilegedActionException pae) {
|
|
||||||
throw (IOException)pae.getException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if init() throws some other RuntimeException,
|
|
||||||
// let it percolate up naturally.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read and initialize the entire login Configuration from the configured
|
|
||||||
* URL.
|
|
||||||
*
|
|
||||||
* @throws IOException if the Configuration can not be initialized
|
|
||||||
* @throws SecurityException if the caller does not have permission
|
|
||||||
* to initialize the Configuration
|
|
||||||
*/
|
|
||||||
private void init() throws IOException {
|
|
||||||
|
|
||||||
boolean initialized = false;
|
|
||||||
|
|
||||||
// For policy.expandProperties, check if either a security or system
|
|
||||||
// property is set to false (old code erroneously checked the system
|
|
||||||
// prop so we must check both to preserve compatibility).
|
|
||||||
String expand = Security.getProperty("policy.expandProperties");
|
|
||||||
if (expand == null) {
|
|
||||||
expand = System.getProperty("policy.expandProperties");
|
|
||||||
}
|
|
||||||
if ("false".equals(expand)) {
|
|
||||||
expandProp = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// new configuration
|
|
||||||
Map<String, List<AppConfigurationEntry>> newConfig = new HashMap<>();
|
|
||||||
|
|
||||||
if (url != null) {
|
|
||||||
/**
|
|
||||||
* If the caller specified a URI via Configuration.getInstance,
|
|
||||||
* we only read from that URI
|
|
||||||
*/
|
|
||||||
if (debugConfig != null) {
|
|
||||||
debugConfig.println("reading " + url);
|
|
||||||
}
|
|
||||||
init(url, newConfig);
|
|
||||||
configuration = newConfig;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Caller did not specify URI via Configuration.getInstance.
|
|
||||||
* Read from URLs listed in the java.security properties file.
|
|
||||||
*/
|
|
||||||
String allowSys = Security.getProperty("policy.allowSystemProperty");
|
|
||||||
|
|
||||||
if ("true".equalsIgnoreCase(allowSys)) {
|
|
||||||
String extra_config = System.getProperty
|
|
||||||
("java.security.auth.login.config");
|
|
||||||
if (extra_config != null) {
|
|
||||||
boolean overrideAll = false;
|
|
||||||
if (extra_config.startsWith("=")) {
|
|
||||||
overrideAll = true;
|
|
||||||
extra_config = extra_config.substring(1);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
extra_config = PropertyExpander.expand(extra_config);
|
|
||||||
} catch (PropertyExpander.ExpandException peee) {
|
|
||||||
MessageFormat form = new MessageFormat
|
|
||||||
(ResourcesMgr.getString
|
|
||||||
("Unable.to.properly.expand.config",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {extra_config};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
URL configURL = null;
|
|
||||||
try {
|
|
||||||
configURL = new URL(extra_config);
|
|
||||||
} catch (MalformedURLException mue) {
|
|
||||||
File configFile = new File(extra_config);
|
|
||||||
if (configFile.exists()) {
|
|
||||||
configURL = configFile.toURI().toURL();
|
|
||||||
} else {
|
|
||||||
MessageFormat form = new MessageFormat
|
|
||||||
(ResourcesMgr.getString
|
|
||||||
("extra.config.No.such.file.or.directory.",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {extra_config};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debugConfig != null) {
|
|
||||||
debugConfig.println("reading "+configURL);
|
|
||||||
}
|
|
||||||
init(configURL, newConfig);
|
|
||||||
initialized = true;
|
|
||||||
if (overrideAll) {
|
|
||||||
if (debugConfig != null) {
|
|
||||||
debugConfig.println("overriding other policies!");
|
|
||||||
}
|
|
||||||
configuration = newConfig;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int n = 1;
|
|
||||||
String config_url;
|
|
||||||
while ((config_url = Security.getProperty
|
|
||||||
("login.config.url."+n)) != null) {
|
|
||||||
try {
|
|
||||||
config_url = PropertyExpander.expand
|
|
||||||
(config_url).replace(File.separatorChar, '/');
|
|
||||||
if (debugConfig != null) {
|
|
||||||
debugConfig.println("\tReading config: " + config_url);
|
|
||||||
}
|
|
||||||
init(new URL(config_url), newConfig);
|
|
||||||
initialized = true;
|
|
||||||
} catch (PropertyExpander.ExpandException peee) {
|
|
||||||
MessageFormat form = new MessageFormat
|
|
||||||
(ResourcesMgr.getString
|
|
||||||
("Unable.to.properly.expand.config",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {config_url};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialized == false && n == 1 && config_url == null) {
|
|
||||||
|
|
||||||
// get the config from the user's home directory
|
|
||||||
if (debugConfig != null) {
|
|
||||||
debugConfig.println("\tReading Policy " +
|
|
||||||
"from ~/.java.login.config");
|
|
||||||
}
|
|
||||||
config_url = System.getProperty("user.home");
|
|
||||||
String userConfigFile = config_url +
|
|
||||||
File.separatorChar + ".java.login.config";
|
|
||||||
|
|
||||||
// No longer throws an exception when there's no config file
|
|
||||||
// at all. Returns an empty Configuration instead.
|
|
||||||
if (new File(userConfigFile).exists()) {
|
|
||||||
init(new File(userConfigFile).toURI().toURL(),
|
|
||||||
newConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configuration = newConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init(URL config,
|
|
||||||
Map<String, List<AppConfigurationEntry>> newConfig)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
try (InputStreamReader isr
|
|
||||||
= new InputStreamReader(getInputStream(config), "UTF-8")) {
|
|
||||||
readConfig(isr, newConfig);
|
|
||||||
} catch (FileNotFoundException fnfe) {
|
|
||||||
if (debugConfig != null) {
|
|
||||||
debugConfig.println(fnfe.toString());
|
|
||||||
}
|
|
||||||
throw new IOException(ResourcesMgr.getString
|
|
||||||
("Configuration.Error.No.such.file.or.directory",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve an entry from the Configuration using an application name
|
|
||||||
* as an index.
|
|
||||||
*
|
|
||||||
* @param applicationName the name used to index the Configuration.
|
|
||||||
* @return an array of AppConfigurationEntries which correspond to
|
|
||||||
* the stacked configuration of LoginModules for this
|
|
||||||
* application, or null if this application has no configured
|
|
||||||
* LoginModules.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public AppConfigurationEntry[] engineGetAppConfigurationEntry
|
|
||||||
(String applicationName) {
|
|
||||||
|
|
||||||
List<AppConfigurationEntry> list = null;
|
|
||||||
synchronized (configuration) {
|
|
||||||
list = configuration.get(applicationName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list == null || list.size() == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
AppConfigurationEntry[] entries =
|
|
||||||
new AppConfigurationEntry[list.size()];
|
|
||||||
Iterator<AppConfigurationEntry> iterator = list.iterator();
|
|
||||||
for (int i = 0; iterator.hasNext(); i++) {
|
|
||||||
AppConfigurationEntry e = iterator.next();
|
|
||||||
entries[i] = new AppConfigurationEntry(e.getLoginModuleName(),
|
|
||||||
e.getControlFlag(),
|
|
||||||
e.getOptions());
|
|
||||||
}
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refresh and reload the Configuration by re-reading all of the
|
|
||||||
* login configurations.
|
|
||||||
*
|
|
||||||
* @throws SecurityException if the caller does not have permission
|
|
||||||
* to refresh the Configuration.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public synchronized void engineRefresh() {
|
|
||||||
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
if (sm != null)
|
|
||||||
sm.checkPermission(new AuthPermission("refreshLoginConfiguration"));
|
|
||||||
|
|
||||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
|
||||||
public Void run() {
|
|
||||||
try {
|
|
||||||
init();
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
throw new SecurityException(ioe.getLocalizedMessage(), ioe);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readConfig(Reader reader,
|
|
||||||
Map<String, List<AppConfigurationEntry>> newConfig)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
linenum = 1;
|
|
||||||
|
|
||||||
if (!(reader instanceof BufferedReader))
|
|
||||||
reader = new BufferedReader(reader);
|
|
||||||
|
|
||||||
st = new StreamTokenizer(reader);
|
|
||||||
st.quoteChar('"');
|
|
||||||
st.wordChars('$', '$');
|
|
||||||
st.wordChars('_', '_');
|
|
||||||
st.wordChars('-', '-');
|
|
||||||
st.wordChars('*', '*');
|
|
||||||
st.lowerCaseMode(false);
|
|
||||||
st.slashSlashComments(true);
|
|
||||||
st.slashStarComments(true);
|
|
||||||
st.eolIsSignificant(true);
|
|
||||||
|
|
||||||
lookahead = nextToken();
|
|
||||||
while (lookahead != StreamTokenizer.TT_EOF) {
|
|
||||||
parseLoginEntry(newConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseLoginEntry(
|
|
||||||
Map<String, List<AppConfigurationEntry>> newConfig)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
List<AppConfigurationEntry> configEntries = new LinkedList<>();
|
|
||||||
|
|
||||||
// application name
|
|
||||||
String appName = st.sval;
|
|
||||||
lookahead = nextToken();
|
|
||||||
|
|
||||||
if (debugParser != null) {
|
|
||||||
debugParser.println("\tReading next config entry: " + appName);
|
|
||||||
}
|
|
||||||
|
|
||||||
match("{");
|
|
||||||
|
|
||||||
// get the modules
|
|
||||||
while (peek("}") == false) {
|
|
||||||
// get the module class name
|
|
||||||
String moduleClass = match("module class name");
|
|
||||||
|
|
||||||
// controlFlag (required, optional, etc)
|
|
||||||
AppConfigurationEntry.LoginModuleControlFlag controlFlag;
|
|
||||||
String sflag = match("controlFlag").toUpperCase();
|
|
||||||
switch (sflag) {
|
|
||||||
case "REQUIRED":
|
|
||||||
controlFlag =
|
|
||||||
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
|
|
||||||
break;
|
|
||||||
case "REQUISITE":
|
|
||||||
controlFlag =
|
|
||||||
AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
|
|
||||||
break;
|
|
||||||
case "SUFFICIENT":
|
|
||||||
controlFlag =
|
|
||||||
AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
|
|
||||||
break;
|
|
||||||
case "OPTIONAL":
|
|
||||||
controlFlag =
|
|
||||||
AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MessageFormat form = new MessageFormat(
|
|
||||||
ResourcesMgr.getString
|
|
||||||
("Configuration.Error.Invalid.control.flag.flag",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {sflag};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the args
|
|
||||||
Map<String, String> options = new HashMap<>();
|
|
||||||
while (peek(";") == false) {
|
|
||||||
String key = match("option key");
|
|
||||||
match("=");
|
|
||||||
try {
|
|
||||||
options.put(key, expand(match("option value")));
|
|
||||||
} catch (PropertyExpander.ExpandException peee) {
|
|
||||||
throw new IOException(peee.getLocalizedMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lookahead = nextToken();
|
|
||||||
|
|
||||||
// create the new element
|
|
||||||
if (debugParser != null) {
|
|
||||||
debugParser.println("\t\t" + moduleClass + ", " + sflag);
|
|
||||||
for (String key : options.keySet()) {
|
|
||||||
debugParser.println("\t\t\t" + key +
|
|
||||||
"=" + options.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
configEntries.add(new AppConfigurationEntry(moduleClass,
|
|
||||||
controlFlag, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
match("}");
|
|
||||||
match(";");
|
|
||||||
|
|
||||||
// add this configuration entry
|
|
||||||
if (newConfig.containsKey(appName)) {
|
|
||||||
MessageFormat form = new MessageFormat(ResourcesMgr.getString
|
|
||||||
("Configuration.Error.Can.not.specify.multiple.entries.for.appName",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {appName};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
newConfig.put(appName, configEntries);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String match(String expect) throws IOException {
|
|
||||||
|
|
||||||
String value = null;
|
|
||||||
|
|
||||||
switch(lookahead) {
|
|
||||||
case StreamTokenizer.TT_EOF:
|
|
||||||
|
|
||||||
MessageFormat form1 = new MessageFormat(ResourcesMgr.getString
|
|
||||||
("Configuration.Error.expected.expect.read.end.of.file.",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source1 = {expect};
|
|
||||||
throw new IOException(form1.format(source1));
|
|
||||||
|
|
||||||
case '"':
|
|
||||||
case StreamTokenizer.TT_WORD:
|
|
||||||
|
|
||||||
if (expect.equalsIgnoreCase("module class name") ||
|
|
||||||
expect.equalsIgnoreCase("controlFlag") ||
|
|
||||||
expect.equalsIgnoreCase("option key") ||
|
|
||||||
expect.equalsIgnoreCase("option value")) {
|
|
||||||
value = st.sval;
|
|
||||||
lookahead = nextToken();
|
|
||||||
} else {
|
|
||||||
MessageFormat form = new MessageFormat(ResourcesMgr.getString
|
|
||||||
("Configuration.Error.Line.line.expected.expect.found.value.",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {new Integer(linenum), expect, st.sval};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '{':
|
|
||||||
|
|
||||||
if (expect.equalsIgnoreCase("{")) {
|
|
||||||
lookahead = nextToken();
|
|
||||||
} else {
|
|
||||||
MessageFormat form = new MessageFormat(ResourcesMgr.getString
|
|
||||||
("Configuration.Error.Line.line.expected.expect.",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {new Integer(linenum), expect, st.sval};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ';':
|
|
||||||
|
|
||||||
if (expect.equalsIgnoreCase(";")) {
|
|
||||||
lookahead = nextToken();
|
|
||||||
} else {
|
|
||||||
MessageFormat form = new MessageFormat(ResourcesMgr.getString
|
|
||||||
("Configuration.Error.Line.line.expected.expect.",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {new Integer(linenum), expect, st.sval};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '}':
|
|
||||||
|
|
||||||
if (expect.equalsIgnoreCase("}")) {
|
|
||||||
lookahead = nextToken();
|
|
||||||
} else {
|
|
||||||
MessageFormat form = new MessageFormat(ResourcesMgr.getString
|
|
||||||
("Configuration.Error.Line.line.expected.expect.",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {new Integer(linenum), expect, st.sval};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '=':
|
|
||||||
|
|
||||||
if (expect.equalsIgnoreCase("=")) {
|
|
||||||
lookahead = nextToken();
|
|
||||||
} else {
|
|
||||||
MessageFormat form = new MessageFormat(ResourcesMgr.getString
|
|
||||||
("Configuration.Error.Line.line.expected.expect.",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {new Integer(linenum), expect, st.sval};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
MessageFormat form = new MessageFormat(ResourcesMgr.getString
|
|
||||||
("Configuration.Error.Line.line.expected.expect.found.value.",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {new Integer(linenum), expect, st.sval};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean peek(String expect) {
|
|
||||||
boolean found = false;
|
|
||||||
|
|
||||||
switch (lookahead) {
|
|
||||||
case ',':
|
|
||||||
if (expect.equalsIgnoreCase(","))
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
case ';':
|
|
||||||
if (expect.equalsIgnoreCase(";"))
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
case '{':
|
|
||||||
if (expect.equalsIgnoreCase("{"))
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
case '}':
|
|
||||||
if (expect.equalsIgnoreCase("}"))
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int nextToken() throws IOException {
|
|
||||||
int tok;
|
|
||||||
while ((tok = st.nextToken()) == StreamTokenizer.TT_EOL) {
|
|
||||||
linenum++;
|
|
||||||
}
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
private InputStream getInputStream(URL url) throws IOException {
|
|
||||||
if ("file".equalsIgnoreCase(url.getProtocol())) {
|
|
||||||
// Compatibility notes:
|
|
||||||
//
|
|
||||||
// Code changed from
|
|
||||||
// String path = url.getFile().replace('/', File.separatorChar);
|
|
||||||
// return new FileInputStream(path);
|
|
||||||
//
|
|
||||||
// The original implementation would search for "/tmp/a%20b"
|
|
||||||
// when url is "file:///tmp/a%20b". This is incorrect. The
|
|
||||||
// current codes fix this bug and searches for "/tmp/a b".
|
|
||||||
// For compatibility reasons, when the file "/tmp/a b" does
|
|
||||||
// not exist, the file named "/tmp/a%20b" will be tried.
|
|
||||||
//
|
|
||||||
// This also means that if both file exists, the behavior of
|
|
||||||
// this method is changed, and the current codes choose the
|
|
||||||
// correct one.
|
|
||||||
try {
|
|
||||||
return url.openStream();
|
|
||||||
} catch (Exception e) {
|
|
||||||
String file = url.getPath();
|
|
||||||
if (url.getHost().length() > 0) { // For Windows UNC
|
|
||||||
file = "//" + url.getHost() + file;
|
|
||||||
}
|
|
||||||
if (debugConfig != null) {
|
|
||||||
debugConfig.println("cannot read " + url +
|
|
||||||
", try " + file);
|
|
||||||
}
|
|
||||||
return new FileInputStream(file);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return url.openStream();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String expand(String value)
|
|
||||||
throws PropertyExpander.ExpandException, IOException {
|
|
||||||
|
|
||||||
if (value.isEmpty()) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expandProp) {
|
|
||||||
|
|
||||||
String s = PropertyExpander.expand(value);
|
|
||||||
|
|
||||||
if (s == null || s.length() == 0) {
|
|
||||||
MessageFormat form = new MessageFormat(ResourcesMgr.getString
|
|
||||||
("Configuration.Error.Line.line.system.property.value.expanded.to.empty.value",
|
|
||||||
"sun.security.util.AuthResources"));
|
|
||||||
Object[] source = {new Integer(linenum), value};
|
|
||||||
throw new IOException(form.format(source));
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -242,7 +242,7 @@ final class SunEntries {
|
|||||||
* Configuration
|
* Configuration
|
||||||
*/
|
*/
|
||||||
map.put("Configuration.JavaLoginConfig",
|
map.put("Configuration.JavaLoginConfig",
|
||||||
"sun.security.provider.ConfigSpiFile");
|
"sun.security.provider.ConfigFile$Spi");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CertPathBuilder
|
* CertPathBuilder
|
||||||
|
@ -132,7 +132,7 @@ securerandom.strongAlgorithms=NativePRNGBlocking:SUN
|
|||||||
# Class to instantiate as the javax.security.auth.login.Configuration
|
# Class to instantiate as the javax.security.auth.login.Configuration
|
||||||
# provider.
|
# provider.
|
||||||
#
|
#
|
||||||
login.configuration.provider=com.sun.security.auth.login.ConfigFile
|
login.configuration.provider=sun.security.provider.ConfigFile
|
||||||
|
|
||||||
#
|
#
|
||||||
# Default login configuration file
|
# Default login configuration file
|
||||||
|
@ -133,7 +133,7 @@ securerandom.strongAlgorithms=NativePRNGBlocking:SUN
|
|||||||
# Class to instantiate as the javax.security.auth.login.Configuration
|
# Class to instantiate as the javax.security.auth.login.Configuration
|
||||||
# provider.
|
# provider.
|
||||||
#
|
#
|
||||||
login.configuration.provider=com.sun.security.auth.login.ConfigFile
|
login.configuration.provider=sun.security.provider.ConfigFile
|
||||||
|
|
||||||
#
|
#
|
||||||
# Default login configuration file
|
# Default login configuration file
|
||||||
|
@ -134,7 +134,7 @@ securerandom.strongAlgorithms=NativePRNGBlocking:SUN
|
|||||||
# Class to instantiate as the javax.security.auth.login.Configuration
|
# Class to instantiate as the javax.security.auth.login.Configuration
|
||||||
# provider.
|
# provider.
|
||||||
#
|
#
|
||||||
login.configuration.provider=com.sun.security.auth.login.ConfigFile
|
login.configuration.provider=sun.security.provider.ConfigFile
|
||||||
|
|
||||||
#
|
#
|
||||||
# Default login configuration file
|
# Default login configuration file
|
||||||
|
@ -133,7 +133,7 @@ securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI
|
|||||||
# Class to instantiate as the javax.security.auth.login.Configuration
|
# Class to instantiate as the javax.security.auth.login.Configuration
|
||||||
# provider.
|
# provider.
|
||||||
#
|
#
|
||||||
login.configuration.provider=com.sun.security.auth.login.ConfigFile
|
login.configuration.provider=sun.security.provider.ConfigFile
|
||||||
|
|
||||||
#
|
#
|
||||||
# Default login configuration file
|
# Default login configuration file
|
||||||
|
Loading…
Reference in New Issue
Block a user