# HG changeset patch # User mullan # Date 1376312631 14400 # Node ID a7b34a4b1fcbe8b29553cf3e687d17604d1654ba # Parent f2358d18923a898489950c153f2e6d42e6330b8f 8016848: javax_security/auth/login tests fail in compact 1 and 2 profiles Summary: Change the default value of the "login.configuration.provider" security property to sun.security.provider.ConfigFile Reviewed-by: xuelei diff -r f2358d18923a -r a7b34a4b1fcb jdk/src/share/classes/com/sun/security/auth/login/ConfigFile.java --- a/jdk/src/share/classes/com/sun/security/auth/login/ConfigFile.java Mon Jul 29 19:36:54 2013 -0700 +++ b/jdk/src/share/classes/com/sun/security/auth/login/ConfigFile.java Mon Aug 12 09:03:51 2013 -0400 @@ -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 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 @@ */ 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 @@ * initialized */ public ConfigFile() { - configFile = new sun.security.provider.ConfigSpiFile(); + spi = new sun.security.provider.ConfigFile.Spi(); } /** @@ -106,7 +106,7 @@ * @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 AppConfigurationEntry[] getAppConfigurationEntry (String applicationName) { - return configFile.engineGetAppConfigurationEntry(applicationName); + return spi.engineGetAppConfigurationEntry(applicationName); } /** @@ -134,7 +134,7 @@ * to refresh the {@code Configuration} */ @Override - public synchronized void refresh() { - configFile.engineRefresh(); + public void refresh() { + spi.engineRefresh(); } } diff -r f2358d18923a -r a7b34a4b1fcb jdk/src/share/classes/javax/security/auth/login/Configuration.java --- a/jdk/src/share/classes/javax/security/auth/login/Configuration.java Mon Jul 29 19:36:54 2013 -0700 +++ b/jdk/src/share/classes/javax/security/auth/login/Configuration.java Mon Aug 12 09:03:51 2013 -0400 @@ -75,7 +75,7 @@ * 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 @@ } }); if (config_class == null) { - config_class = "com.sun.security.auth.login.ConfigFile"; + config_class = "sun.security.provider.ConfigFile"; } try { diff -r f2358d18923a -r a7b34a4b1fcb jdk/src/share/classes/sun/security/provider/ConfigFile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/security/provider/ConfigFile.java Mon Aug 12 09:03:51 2013 -0400 @@ -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: + * + *

    + *
  1. + * 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. + * + *
  2. + * 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. + * + *
  3. + * 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. + * + *
  4. + * 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 -r f2358d18923a -r a7b34a4b1fcb jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java --- a/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java Mon Jul 29 19:36:54 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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: - * - *

    - *
  1. - * 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. - * - *
  2. - * 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. - * - *
  3. - * 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. - * - *
  4. - * 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 -r f2358d18923a -r a7b34a4b1fcb jdk/src/share/classes/sun/security/provider/SunEntries.java --- a/jdk/src/share/classes/sun/security/provider/SunEntries.java Mon Jul 29 19:36:54 2013 -0700 +++ b/jdk/src/share/classes/sun/security/provider/SunEntries.java Mon Aug 12 09:03:51 2013 -0400 @@ -242,7 +242,7 @@ * Configuration */ map.put("Configuration.JavaLoginConfig", - "sun.security.provider.ConfigSpiFile"); + "sun.security.provider.ConfigFile$Spi"); /* * CertPathBuilder diff -r f2358d18923a -r a7b34a4b1fcb jdk/src/share/lib/security/java.security-linux --- a/jdk/src/share/lib/security/java.security-linux Mon Jul 29 19:36:54 2013 -0700 +++ b/jdk/src/share/lib/security/java.security-linux Mon Aug 12 09:03:51 2013 -0400 @@ -132,7 +132,7 @@ # 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 -r f2358d18923a -r a7b34a4b1fcb jdk/src/share/lib/security/java.security-macosx --- a/jdk/src/share/lib/security/java.security-macosx Mon Jul 29 19:36:54 2013 -0700 +++ b/jdk/src/share/lib/security/java.security-macosx Mon Aug 12 09:03:51 2013 -0400 @@ -133,7 +133,7 @@ # 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 -r f2358d18923a -r a7b34a4b1fcb jdk/src/share/lib/security/java.security-solaris --- a/jdk/src/share/lib/security/java.security-solaris Mon Jul 29 19:36:54 2013 -0700 +++ b/jdk/src/share/lib/security/java.security-solaris Mon Aug 12 09:03:51 2013 -0400 @@ -134,7 +134,7 @@ # 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 -r f2358d18923a -r a7b34a4b1fcb jdk/src/share/lib/security/java.security-windows --- a/jdk/src/share/lib/security/java.security-windows Mon Jul 29 19:36:54 2013 -0700 +++ b/jdk/src/share/lib/security/java.security-windows Mon Aug 12 09:03:51 2013 -0400 @@ -133,7 +133,7 @@ # 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