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

Save This Page
Home » openjdk-7 » com.sun.security » auth » login » [javadoc | source]