diff --git a/jdk/src/share/classes/com/sun/security/auth/login/ConfigFile.java b/jdk/src/share/classes/com/sun/security/auth/login/ConfigFile.java
index 22a1ffbe21b..3e6dc7da579 100644
--- a/jdk/src/share/classes/com/sun/security/auth/login/ConfigFile.java
+++ b/jdk/src/share/classes/com/sun/security/auth/login/ConfigFile.java
@@ -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.
*
* 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;
// 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
-// sun.security.provider.ConfigSpiFile and not this class.
+// sun.security.provider.ConfigFile.Spi and not this class.
// See JDK-8005117 for more information.
/**
@@ -85,7 +85,7 @@ import java.net.URI;
*/
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.
@@ -94,7 +94,7 @@ public class ConfigFile extends Configuration {
* initialized
*/
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
*/
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
(String applicationName) {
- return configFile.engineGetAppConfigurationEntry(applicationName);
+ return spi.engineGetAppConfigurationEntry(applicationName);
}
/**
@@ -134,7 +134,7 @@ public class ConfigFile extends Configuration {
* to refresh the {@code Configuration}
*/
@Override
- public synchronized void refresh() {
- configFile.engineRefresh();
+ public void refresh() {
+ spi.engineRefresh();
}
}
diff --git a/jdk/src/share/classes/javax/security/auth/login/Configuration.java b/jdk/src/share/classes/javax/security/auth/login/Configuration.java
index ff10a3bbf14..c74901bd3ba 100644
--- a/jdk/src/share/classes/javax/security/auth/login/Configuration.java
+++ b/jdk/src/share/classes/javax/security/auth/login/Configuration.java
@@ -75,7 +75,7 @@ import sun.security.jca.GetInstance;
* 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 specific entry,
+ * If an application does not have a specific entry,
* it defaults to the specific entry for "other".
*
*
The Flag value controls the overall behavior as authentication
@@ -248,7 +248,7 @@ public abstract class Configuration {
}
});
if (config_class == null) {
- config_class = "com.sun.security.auth.login.ConfigFile";
+ config_class = "sun.security.provider.ConfigFile";
}
try {
diff --git a/jdk/src/share/classes/sun/security/provider/ConfigFile.java b/jdk/src/share/classes/sun/security/provider/ConfigFile.java
new file mode 100644
index 00000000000..f3c041ac0b3
--- /dev/null
+++ b/jdk/src/share/classes/sun/security/provider/ConfigFile.java
@@ -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}.
+ *
+ *
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:
+ *
+ *
+ * -
+ * Loop through the security properties,
+ * login.config.url.1, login.config.url.2, ...,
+ * login.config.url.X.
+ * Each property value specifies a {@code URL} pointing to a
+ * login configuration file to be loaded. Read in and load
+ * each configuration.
+ *
+ *
-
+ * The {@code java.lang.System} property
+ * java.security.auth.login.config
+ * 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,
+ * policy.allowSystemProperty is set to true),
+ * also load that login configuration.
+ *
+ *
-
+ * If the java.security.auth.login.config property is defined using
+ * "==" (rather than "="), then ignore all other specified
+ * login configurations and only load this configuration.
+ *
+ *
-
+ * 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.
+ *
+ *
+ * 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> 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() {
+ 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> 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> 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 list = null;
+ synchronized (configuration) {
+ list = configuration.get(applicationName);
+ }
+
+ if (list == null || list.size() == 0) {
+ return null;
+ }
+
+ AppConfigurationEntry[] entries =
+ new AppConfigurationEntry[list.size()];
+ Iterator 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() {
+ public Void run() {
+ try {
+ init();
+ } catch (IOException ioe) {
+ throw new SecurityException(ioe.getLocalizedMessage(),
+ ioe);
+ }
+ return null;
+ }
+ });
+ }
+
+ private void readConfig(Reader reader,
+ Map> 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> newConfig)
+ throws IOException {
+
+ List 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 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));
+ }
+ }
+}
diff --git a/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java b/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java
deleted file mode 100644
index 03cdc5712d0..00000000000
--- a/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java
+++ /dev/null
@@ -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}.
- *
- * 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:
- *
- *
- * -
- * Loop through the security properties,
- * login.config.url.1, login.config.url.2, ...,
- * login.config.url.X.
- * Each property value specifies a
URL
pointing to a
- * login configuration file to be loaded. Read in and load
- * each configuration.
- *
- * -
- * The {@code java.lang.System} property
- * java.security.auth.login.config
- * 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,
- * policy.allowSystemProperty is set to true),
- * also load that login configuration.
- *
- *
-
- * If the java.security.auth.login.config property is defined using
- * "==" (rather than "="), then ignore all other specified
- * login configurations and only load this configuration.
- *
- *
-
- * 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.
- *
- *
- * 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> 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() {
- 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> 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> 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 list = null;
- synchronized (configuration) {
- list = configuration.get(applicationName);
- }
-
- if (list == null || list.size() == 0)
- return null;
-
- AppConfigurationEntry[] entries =
- new AppConfigurationEntry[list.size()];
- Iterator 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() {
- public Void run() {
- try {
- init();
- } catch (IOException ioe) {
- throw new SecurityException(ioe.getLocalizedMessage(), ioe);
- }
- return null;
- }
- });
- }
-
- private void readConfig(Reader reader,
- Map> 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> newConfig)
- throws IOException {
-
- List 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 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;
- }
- }
-}
diff --git a/jdk/src/share/classes/sun/security/provider/SunEntries.java b/jdk/src/share/classes/sun/security/provider/SunEntries.java
index 3143093f2d5..5a14e7bd702 100644
--- a/jdk/src/share/classes/sun/security/provider/SunEntries.java
+++ b/jdk/src/share/classes/sun/security/provider/SunEntries.java
@@ -242,7 +242,7 @@ final class SunEntries {
* Configuration
*/
map.put("Configuration.JavaLoginConfig",
- "sun.security.provider.ConfigSpiFile");
+ "sun.security.provider.ConfigFile$Spi");
/*
* CertPathBuilder
diff --git a/jdk/src/share/lib/security/java.security-linux b/jdk/src/share/lib/security/java.security-linux
index 935a10fc00a..2686cae4c4f 100644
--- a/jdk/src/share/lib/security/java.security-linux
+++ b/jdk/src/share/lib/security/java.security-linux
@@ -132,7 +132,7 @@ securerandom.strongAlgorithms=NativePRNGBlocking:SUN
# Class to instantiate as the javax.security.auth.login.Configuration
# provider.
#
-login.configuration.provider=com.sun.security.auth.login.ConfigFile
+login.configuration.provider=sun.security.provider.ConfigFile
#
# Default login configuration file
diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx
index c30834ad220..7ea2ee18735 100644
--- a/jdk/src/share/lib/security/java.security-macosx
+++ b/jdk/src/share/lib/security/java.security-macosx
@@ -133,7 +133,7 @@ securerandom.strongAlgorithms=NativePRNGBlocking:SUN
# Class to instantiate as the javax.security.auth.login.Configuration
# provider.
#
-login.configuration.provider=com.sun.security.auth.login.ConfigFile
+login.configuration.provider=sun.security.provider.ConfigFile
#
# Default login configuration file
diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris
index 35414ba9244..be885d3b187 100644
--- a/jdk/src/share/lib/security/java.security-solaris
+++ b/jdk/src/share/lib/security/java.security-solaris
@@ -134,7 +134,7 @@ securerandom.strongAlgorithms=NativePRNGBlocking:SUN
# Class to instantiate as the javax.security.auth.login.Configuration
# provider.
#
-login.configuration.provider=com.sun.security.auth.login.ConfigFile
+login.configuration.provider=sun.security.provider.ConfigFile
#
# Default login configuration file
diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows
index 88293ad60da..c06a56156ae 100644
--- a/jdk/src/share/lib/security/java.security-windows
+++ b/jdk/src/share/lib/security/java.security-windows
@@ -133,7 +133,7 @@ securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI
# Class to instantiate as the javax.security.auth.login.Configuration
# provider.
#
-login.configuration.provider=com.sun.security.auth.login.ConfigFile
+login.configuration.provider=sun.security.provider.ConfigFile
#
# Default login configuration file