src/java.base/share/classes/sun/security/provider/ConfigFile.java
changeset 47216 71c04702a3d5
parent 43243 a48dab17a356
child 53018 8bf9268df0e2
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.security.provider;
       
    27 
       
    28 import java.io.*;
       
    29 import java.net.MalformedURLException;
       
    30 import java.net.URI;
       
    31 import java.net.URL;
       
    32 import java.security.AccessController;
       
    33 import java.security.PrivilegedAction;
       
    34 import java.security.PrivilegedActionException;
       
    35 import java.security.PrivilegedExceptionAction;
       
    36 import java.security.Security;
       
    37 import java.security.URIParameter;
       
    38 import java.text.MessageFormat;
       
    39 import java.util.*;
       
    40 import javax.security.auth.AuthPermission;
       
    41 import javax.security.auth.login.AppConfigurationEntry;
       
    42 import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
       
    43 import javax.security.auth.login.Configuration;
       
    44 import javax.security.auth.login.ConfigurationSpi;
       
    45 import sun.security.util.Debug;
       
    46 import sun.security.util.PropertyExpander;
       
    47 import sun.security.util.ResourcesMgr;
       
    48 
       
    49 /**
       
    50  * This class represents a default implementation for
       
    51  * {@code javax.security.auth.login.Configuration}.
       
    52  *
       
    53  * <p> This object stores the runtime login configuration representation,
       
    54  * and is the amalgamation of multiple static login configurations that
       
    55  * resides in files. The algorithm for locating the login configuration
       
    56  * file(s) and reading their information into this {@code Configuration}
       
    57  * object is:
       
    58  *
       
    59  * <ol>
       
    60  * <li>
       
    61  *   Loop through the security properties,
       
    62  *   <i>login.config.url.1</i>, <i>login.config.url.2</i>, ...,
       
    63  *   <i>login.config.url.X</i>.
       
    64  *   Each property value specifies a {@code URL} pointing to a
       
    65  *   login configuration file to be loaded.  Read in and load
       
    66  *   each configuration.
       
    67  *
       
    68  * <li>
       
    69  *   The {@code java.lang.System} property
       
    70  *   <i>java.security.auth.login.config</i>
       
    71  *   may also be set to a {@code URL} pointing to another
       
    72  *   login configuration file
       
    73  *   (which is the case when a user uses the -D switch at runtime).
       
    74  *   If this property is defined, and its use is allowed by the
       
    75  *   security property file (the Security property,
       
    76  *   <i>policy.allowSystemProperty</i> is set to <i>true</i>),
       
    77  *   also load that login configuration.
       
    78  *
       
    79  * <li>
       
    80  *   If the <i>java.security.auth.login.config</i> property is defined using
       
    81  *   "==" (rather than "="), then ignore all other specified
       
    82  *   login configurations and only load this configuration.
       
    83  *
       
    84  * <li>
       
    85  *   If no system or security properties were set, try to read from the file,
       
    86  *   ${user.home}/.java.login.config, where ${user.home} is the value
       
    87  *   represented by the "user.home" System property.
       
    88  * </ol>
       
    89  *
       
    90  * <p> The configuration syntax supported by this implementation
       
    91  * is exactly that syntax specified in the
       
    92  * {@code javax.security.auth.login.Configuration} class.
       
    93  *
       
    94  * @see javax.security.auth.login.LoginContext
       
    95  * @see java.security.Security security properties
       
    96  */
       
    97 public final class ConfigFile extends Configuration {
       
    98 
       
    99     private final Spi spi;
       
   100 
       
   101     public ConfigFile() {
       
   102         spi = new Spi();
       
   103     }
       
   104 
       
   105     @Override
       
   106     public AppConfigurationEntry[] getAppConfigurationEntry(String appName) {
       
   107         return spi.engineGetAppConfigurationEntry(appName);
       
   108     }
       
   109 
       
   110     @Override
       
   111     public synchronized void refresh() {
       
   112         spi.engineRefresh();
       
   113     }
       
   114 
       
   115     public static final class Spi extends ConfigurationSpi {
       
   116 
       
   117         private URL url;
       
   118         private boolean expandProp = true;
       
   119         private Map<String, List<AppConfigurationEntry>> configuration;
       
   120         private int linenum;
       
   121         private StreamTokenizer st;
       
   122         private int lookahead;
       
   123 
       
   124         private static Debug debugConfig = Debug.getInstance("configfile");
       
   125         private static Debug debugParser = Debug.getInstance("configparser");
       
   126 
       
   127         /**
       
   128          * Creates a new {@code ConfigurationSpi} object.
       
   129          *
       
   130          * @throws SecurityException if the {@code ConfigurationSpi} can not be
       
   131          *                           initialized
       
   132          */
       
   133         public Spi() {
       
   134             try {
       
   135                 init();
       
   136             } catch (IOException ioe) {
       
   137                 throw new SecurityException(ioe);
       
   138             }
       
   139         }
       
   140 
       
   141         /**
       
   142          * Creates a new {@code ConfigurationSpi} object from the specified
       
   143          * {@code URI}.
       
   144          *
       
   145          * @param uri the {@code URI}
       
   146          * @throws SecurityException if the {@code ConfigurationSpi} can not be
       
   147          *                           initialized
       
   148          * @throws NullPointerException if {@code uri} is null
       
   149          */
       
   150         public Spi(URI uri) {
       
   151             // only load config from the specified URI
       
   152             try {
       
   153                 url = uri.toURL();
       
   154                 init();
       
   155             } catch (IOException ioe) {
       
   156                 throw new SecurityException(ioe);
       
   157             }
       
   158         }
       
   159 
       
   160         public Spi(final Configuration.Parameters params) throws IOException {
       
   161 
       
   162             // call in a doPrivileged
       
   163             //
       
   164             // we have already passed the Configuration.getInstance
       
   165             // security check.  also this class is not freely accessible
       
   166             // (it is in the "sun" package).
       
   167 
       
   168             try {
       
   169                 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
       
   170                     public Void run() throws IOException {
       
   171                         if (params == null) {
       
   172                             init();
       
   173                         } else {
       
   174                             if (!(params instanceof URIParameter)) {
       
   175                                 throw new IllegalArgumentException
       
   176                                         ("Unrecognized parameter: " + params);
       
   177                             }
       
   178                             URIParameter uriParam = (URIParameter)params;
       
   179                             url = uriParam.getURI().toURL();
       
   180                             init();
       
   181                         }
       
   182                         return null;
       
   183                     }
       
   184                 });
       
   185             } catch (PrivilegedActionException pae) {
       
   186                 throw (IOException)pae.getException();
       
   187             }
       
   188 
       
   189             // if init() throws some other RuntimeException,
       
   190             // let it percolate up naturally.
       
   191         }
       
   192 
       
   193         /**
       
   194          * Read and initialize the entire login Configuration from the
       
   195          * configured URL.
       
   196          *
       
   197          * @throws IOException if the Configuration can not be initialized
       
   198          * @throws SecurityException if the caller does not have permission
       
   199          *                           to initialize the Configuration
       
   200          */
       
   201         private void init() throws IOException {
       
   202 
       
   203             boolean initialized = false;
       
   204 
       
   205             // For policy.expandProperties, check if either a security or system
       
   206             // property is set to false (old code erroneously checked the system
       
   207             // prop so we must check both to preserve compatibility).
       
   208             String expand = Security.getProperty("policy.expandProperties");
       
   209             if (expand == null) {
       
   210                 expand = System.getProperty("policy.expandProperties");
       
   211             }
       
   212             if ("false".equals(expand)) {
       
   213                 expandProp = false;
       
   214             }
       
   215 
       
   216             // new configuration
       
   217             Map<String, List<AppConfigurationEntry>> newConfig = new HashMap<>();
       
   218 
       
   219             if (url != null) {
       
   220                 /**
       
   221                  * If the caller specified a URI via Configuration.getInstance,
       
   222                  * we only read from that URI
       
   223                  */
       
   224                 if (debugConfig != null) {
       
   225                     debugConfig.println("reading " + url);
       
   226                 }
       
   227                 init(url, newConfig);
       
   228                 configuration = newConfig;
       
   229                 return;
       
   230             }
       
   231 
       
   232             /**
       
   233              * Caller did not specify URI via Configuration.getInstance.
       
   234              * Read from URLs listed in the java.security properties file.
       
   235              */
       
   236             String allowSys = Security.getProperty("policy.allowSystemProperty");
       
   237 
       
   238             if ("true".equalsIgnoreCase(allowSys)) {
       
   239                 String extra_config = System.getProperty
       
   240                                       ("java.security.auth.login.config");
       
   241                 if (extra_config != null) {
       
   242                     boolean overrideAll = false;
       
   243                     if (extra_config.startsWith("=")) {
       
   244                         overrideAll = true;
       
   245                         extra_config = extra_config.substring(1);
       
   246                     }
       
   247                     try {
       
   248                         extra_config = PropertyExpander.expand(extra_config);
       
   249                     } catch (PropertyExpander.ExpandException peee) {
       
   250                         throw ioException("Unable.to.properly.expand.config",
       
   251                                           extra_config);
       
   252                     }
       
   253 
       
   254                     URL configURL = null;
       
   255                     try {
       
   256                         configURL = new URL(extra_config);
       
   257                     } catch (MalformedURLException mue) {
       
   258                         File configFile = new File(extra_config);
       
   259                         if (configFile.exists()) {
       
   260                             configURL = configFile.toURI().toURL();
       
   261                         } else {
       
   262                             throw ioException(
       
   263                                 "extra.config.No.such.file.or.directory.",
       
   264                                 extra_config);
       
   265                         }
       
   266                     }
       
   267 
       
   268                     if (debugConfig != null) {
       
   269                         debugConfig.println("reading "+configURL);
       
   270                     }
       
   271                     init(configURL, newConfig);
       
   272                     initialized = true;
       
   273                     if (overrideAll) {
       
   274                         if (debugConfig != null) {
       
   275                             debugConfig.println("overriding other policies!");
       
   276                         }
       
   277                         configuration = newConfig;
       
   278                         return;
       
   279                     }
       
   280                 }
       
   281             }
       
   282 
       
   283             int n = 1;
       
   284             String config_url;
       
   285             while ((config_url = Security.getProperty
       
   286                                      ("login.config.url."+n)) != null) {
       
   287                 try {
       
   288                     config_url = PropertyExpander.expand
       
   289                         (config_url).replace(File.separatorChar, '/');
       
   290                     if (debugConfig != null) {
       
   291                         debugConfig.println("\tReading config: " + config_url);
       
   292                     }
       
   293                     init(new URL(config_url), newConfig);
       
   294                     initialized = true;
       
   295                 } catch (PropertyExpander.ExpandException peee) {
       
   296                     throw ioException("Unable.to.properly.expand.config",
       
   297                                       config_url);
       
   298                 }
       
   299                 n++;
       
   300             }
       
   301 
       
   302             if (initialized == false && n == 1 && config_url == null) {
       
   303 
       
   304                 // get the config from the user's home directory
       
   305                 if (debugConfig != null) {
       
   306                     debugConfig.println("\tReading Policy " +
       
   307                                 "from ~/.java.login.config");
       
   308                 }
       
   309                 config_url = System.getProperty("user.home");
       
   310                 String userConfigFile = config_url + File.separatorChar +
       
   311                                         ".java.login.config";
       
   312 
       
   313                 // No longer throws an exception when there's no config file
       
   314                 // at all. Returns an empty Configuration instead.
       
   315                 if (new File(userConfigFile).exists()) {
       
   316                     init(new File(userConfigFile).toURI().toURL(), newConfig);
       
   317                 }
       
   318             }
       
   319 
       
   320             configuration = newConfig;
       
   321         }
       
   322 
       
   323         private void init(URL config,
       
   324                           Map<String, List<AppConfigurationEntry>> newConfig)
       
   325                           throws IOException {
       
   326 
       
   327             try (InputStreamReader isr
       
   328                     = new InputStreamReader(getInputStream(config), "UTF-8")) {
       
   329                 readConfig(isr, newConfig);
       
   330             } catch (FileNotFoundException fnfe) {
       
   331                 if (debugConfig != null) {
       
   332                     debugConfig.println(fnfe.toString());
       
   333                 }
       
   334                 throw new IOException(ResourcesMgr.getAuthResourceString
       
   335                     ("Configuration.Error.No.such.file.or.directory"));
       
   336             }
       
   337         }
       
   338 
       
   339         /**
       
   340          * Retrieve an entry from the Configuration using an application name
       
   341          * as an index.
       
   342          *
       
   343          * @param applicationName the name used to index the Configuration.
       
   344          * @return an array of AppConfigurationEntries which correspond to
       
   345          *         the stacked configuration of LoginModules for this
       
   346          *         application, or null if this application has no configured
       
   347          *         LoginModules.
       
   348          */
       
   349         @Override
       
   350         public AppConfigurationEntry[] engineGetAppConfigurationEntry
       
   351             (String applicationName) {
       
   352 
       
   353             List<AppConfigurationEntry> list = null;
       
   354             synchronized (configuration) {
       
   355                 list = configuration.get(applicationName);
       
   356             }
       
   357 
       
   358             if (list == null || list.size() == 0) {
       
   359                 return null;
       
   360             }
       
   361 
       
   362             AppConfigurationEntry[] entries =
       
   363                                     new AppConfigurationEntry[list.size()];
       
   364             Iterator<AppConfigurationEntry> iterator = list.iterator();
       
   365             for (int i = 0; iterator.hasNext(); i++) {
       
   366                 AppConfigurationEntry e = iterator.next();
       
   367                 entries[i] = new AppConfigurationEntry(e.getLoginModuleName(),
       
   368                                                        e.getControlFlag(),
       
   369                                                        e.getOptions());
       
   370             }
       
   371             return entries;
       
   372         }
       
   373 
       
   374         /**
       
   375          * Refresh and reload the Configuration by re-reading all of the
       
   376          * login configurations.
       
   377          *
       
   378          * @throws SecurityException if the caller does not have permission
       
   379          *                           to refresh the Configuration.
       
   380          */
       
   381         @Override
       
   382         public synchronized void engineRefresh() {
       
   383 
       
   384             SecurityManager sm = System.getSecurityManager();
       
   385             if (sm != null) {
       
   386                 sm.checkPermission(
       
   387                     new AuthPermission("refreshLoginConfiguration"));
       
   388             }
       
   389 
       
   390             AccessController.doPrivileged(new PrivilegedAction<Void>() {
       
   391                 public Void run() {
       
   392                     try {
       
   393                         init();
       
   394                     } catch (IOException ioe) {
       
   395                         throw new SecurityException(ioe.getLocalizedMessage(),
       
   396                                                     ioe);
       
   397                     }
       
   398                     return null;
       
   399                 }
       
   400             });
       
   401         }
       
   402 
       
   403         private void readConfig(Reader reader,
       
   404             Map<String, List<AppConfigurationEntry>> newConfig)
       
   405             throws IOException {
       
   406 
       
   407             linenum = 1;
       
   408 
       
   409             if (!(reader instanceof BufferedReader)) {
       
   410                 reader = new BufferedReader(reader);
       
   411             }
       
   412 
       
   413             st = new StreamTokenizer(reader);
       
   414             st.quoteChar('"');
       
   415             st.wordChars('$', '$');
       
   416             st.wordChars('_', '_');
       
   417             st.wordChars('-', '-');
       
   418             st.wordChars('*', '*');
       
   419             st.lowerCaseMode(false);
       
   420             st.slashSlashComments(true);
       
   421             st.slashStarComments(true);
       
   422             st.eolIsSignificant(true);
       
   423 
       
   424             lookahead = nextToken();
       
   425             while (lookahead != StreamTokenizer.TT_EOF) {
       
   426                 parseLoginEntry(newConfig);
       
   427             }
       
   428         }
       
   429 
       
   430         private void parseLoginEntry(
       
   431             Map<String, List<AppConfigurationEntry>> newConfig)
       
   432             throws IOException {
       
   433 
       
   434             List<AppConfigurationEntry> configEntries = new LinkedList<>();
       
   435 
       
   436             // application name
       
   437             String appName = st.sval;
       
   438             lookahead = nextToken();
       
   439 
       
   440             if (debugParser != null) {
       
   441                 debugParser.println("\tReading next config entry: " + appName);
       
   442             }
       
   443 
       
   444             match("{");
       
   445 
       
   446             // get the modules
       
   447             while (peek("}") == false) {
       
   448                 // get the module class name
       
   449                 String moduleClass = match("module class name");
       
   450 
       
   451                 // controlFlag (required, optional, etc)
       
   452                 LoginModuleControlFlag controlFlag;
       
   453                 String sflag = match("controlFlag").toUpperCase(Locale.ENGLISH);
       
   454                 switch (sflag) {
       
   455                     case "REQUIRED":
       
   456                         controlFlag = LoginModuleControlFlag.REQUIRED;
       
   457                         break;
       
   458                     case "REQUISITE":
       
   459                         controlFlag = LoginModuleControlFlag.REQUISITE;
       
   460                         break;
       
   461                     case "SUFFICIENT":
       
   462                         controlFlag = LoginModuleControlFlag.SUFFICIENT;
       
   463                         break;
       
   464                     case "OPTIONAL":
       
   465                         controlFlag = LoginModuleControlFlag.OPTIONAL;
       
   466                         break;
       
   467                     default:
       
   468                         throw ioException(
       
   469                             "Configuration.Error.Invalid.control.flag.flag",
       
   470                             sflag);
       
   471                 }
       
   472 
       
   473                 // get the args
       
   474                 Map<String, String> options = new HashMap<>();
       
   475                 while (peek(";") == false) {
       
   476                     String key = match("option key");
       
   477                     match("=");
       
   478                     try {
       
   479                         options.put(key, expand(match("option value")));
       
   480                     } catch (PropertyExpander.ExpandException peee) {
       
   481                         throw new IOException(peee.getLocalizedMessage());
       
   482                     }
       
   483                 }
       
   484 
       
   485                 lookahead = nextToken();
       
   486 
       
   487                 // create the new element
       
   488                 if (debugParser != null) {
       
   489                     debugParser.println("\t\t" + moduleClass + ", " + sflag);
       
   490                     for (String key : options.keySet()) {
       
   491                         debugParser.println("\t\t\t" + key +
       
   492                                             "=" + options.get(key));
       
   493                     }
       
   494                 }
       
   495                 configEntries.add(new AppConfigurationEntry(moduleClass,
       
   496                                                             controlFlag,
       
   497                                                             options));
       
   498             }
       
   499 
       
   500             match("}");
       
   501             match(";");
       
   502 
       
   503             // add this configuration entry
       
   504             if (newConfig.containsKey(appName)) {
       
   505                 throw ioException(
       
   506                     "Configuration.Error.Can.not.specify.multiple.entries.for.appName",
       
   507                     appName);
       
   508             }
       
   509             newConfig.put(appName, configEntries);
       
   510         }
       
   511 
       
   512         private String match(String expect) throws IOException {
       
   513 
       
   514             String value = null;
       
   515 
       
   516             switch(lookahead) {
       
   517             case StreamTokenizer.TT_EOF:
       
   518                 throw ioException(
       
   519                     "Configuration.Error.expected.expect.read.end.of.file.",
       
   520                     expect);
       
   521 
       
   522             case '"':
       
   523             case StreamTokenizer.TT_WORD:
       
   524                 if (expect.equalsIgnoreCase("module class name") ||
       
   525                     expect.equalsIgnoreCase("controlFlag") ||
       
   526                     expect.equalsIgnoreCase("option key") ||
       
   527                     expect.equalsIgnoreCase("option value")) {
       
   528                     value = st.sval;
       
   529                     lookahead = nextToken();
       
   530                 } else {
       
   531                     throw ioException(
       
   532                         "Configuration.Error.Line.line.expected.expect.found.value.",
       
   533                         linenum, expect, st.sval);
       
   534                 }
       
   535                 break;
       
   536 
       
   537             case '{':
       
   538                 if (expect.equalsIgnoreCase("{")) {
       
   539                     lookahead = nextToken();
       
   540                 } else {
       
   541                     throw ioException(
       
   542                         "Configuration.Error.Line.line.expected.expect.",
       
   543                         linenum, expect, st.sval);
       
   544                 }
       
   545                 break;
       
   546 
       
   547             case ';':
       
   548                 if (expect.equalsIgnoreCase(";")) {
       
   549                     lookahead = nextToken();
       
   550                 } else {
       
   551                     throw ioException(
       
   552                         "Configuration.Error.Line.line.expected.expect.",
       
   553                         linenum, expect, st.sval);
       
   554                 }
       
   555                 break;
       
   556 
       
   557             case '}':
       
   558                 if (expect.equalsIgnoreCase("}")) {
       
   559                     lookahead = nextToken();
       
   560                 } else {
       
   561                     throw ioException(
       
   562                         "Configuration.Error.Line.line.expected.expect.",
       
   563                         linenum, expect, st.sval);
       
   564                 }
       
   565                 break;
       
   566 
       
   567             case '=':
       
   568                 if (expect.equalsIgnoreCase("=")) {
       
   569                     lookahead = nextToken();
       
   570                 } else {
       
   571                     throw ioException(
       
   572                         "Configuration.Error.Line.line.expected.expect.",
       
   573                         linenum, expect, st.sval);
       
   574                 }
       
   575                 break;
       
   576 
       
   577             default:
       
   578                 throw ioException(
       
   579                     "Configuration.Error.Line.line.expected.expect.found.value.",
       
   580                     linenum, expect, st.sval);
       
   581             }
       
   582             return value;
       
   583         }
       
   584 
       
   585         private boolean peek(String expect) {
       
   586             switch (lookahead) {
       
   587                 case ',':
       
   588                     return expect.equalsIgnoreCase(",");
       
   589                 case ';':
       
   590                     return expect.equalsIgnoreCase(";");
       
   591                 case '{':
       
   592                     return expect.equalsIgnoreCase("{");
       
   593                 case '}':
       
   594                     return expect.equalsIgnoreCase("}");
       
   595                 default:
       
   596                     return false;
       
   597             }
       
   598         }
       
   599 
       
   600         private int nextToken() throws IOException {
       
   601             int tok;
       
   602             while ((tok = st.nextToken()) == StreamTokenizer.TT_EOL) {
       
   603                 linenum++;
       
   604             }
       
   605             return tok;
       
   606         }
       
   607 
       
   608         private InputStream getInputStream(URL url) throws IOException {
       
   609             if ("file".equalsIgnoreCase(url.getProtocol())) {
       
   610                 // Compatibility notes:
       
   611                 //
       
   612                 // Code changed from
       
   613                 //   String path = url.getFile().replace('/', File.separatorChar);
       
   614                 //   return new FileInputStream(path);
       
   615                 //
       
   616                 // The original implementation would search for "/tmp/a%20b"
       
   617                 // when url is "file:///tmp/a%20b". This is incorrect. The
       
   618                 // current codes fix this bug and searches for "/tmp/a b".
       
   619                 // For compatibility reasons, when the file "/tmp/a b" does
       
   620                 // not exist, the file named "/tmp/a%20b" will be tried.
       
   621                 //
       
   622                 // This also means that if both file exists, the behavior of
       
   623                 // this method is changed, and the current codes choose the
       
   624                 // correct one.
       
   625                 try {
       
   626                     return url.openStream();
       
   627                 } catch (Exception e) {
       
   628                     String file = url.getPath();
       
   629                     if (url.getHost().length() > 0) {  // For Windows UNC
       
   630                         file = "//" + url.getHost() + file;
       
   631                     }
       
   632                     if (debugConfig != null) {
       
   633                         debugConfig.println("cannot read " + url +
       
   634                                             ", try " + file);
       
   635                     }
       
   636                     return new FileInputStream(file);
       
   637                 }
       
   638             } else {
       
   639                 return url.openStream();
       
   640             }
       
   641         }
       
   642 
       
   643         private String expand(String value)
       
   644             throws PropertyExpander.ExpandException, IOException {
       
   645 
       
   646             if (value.isEmpty()) {
       
   647                 return value;
       
   648             }
       
   649 
       
   650             if (!expandProp) {
       
   651                 return value;
       
   652             }
       
   653             String s = PropertyExpander.expand(value);
       
   654             if (s == null || s.length() == 0) {
       
   655                 throw ioException(
       
   656                     "Configuration.Error.Line.line.system.property.value.expanded.to.empty.value",
       
   657                     linenum, value);
       
   658             }
       
   659             return s;
       
   660         }
       
   661 
       
   662         private IOException ioException(String resourceKey, Object... args) {
       
   663             MessageFormat form = new MessageFormat(
       
   664                 ResourcesMgr.getAuthResourceString(resourceKey));
       
   665             return new IOException(form.format(args));
       
   666         }
       
   667     }
       
   668 }