Index: ChangeLog =================================================================== RCS file: /cvsroot/classpath/classpath/ChangeLog,v retrieving revision 1.6064 diff -u -r1.6064 ChangeLog --- ChangeLog 14 Jan 2006 11:14:43 -0000 1.6064 +++ ChangeLog 14 Jan 2006 20:03:38 -0000 @@ -1,3 +1,15 @@ +2006-01-15 Raif S. Naffah
+ + * gnu/javax/security/auth/login/ConfigFileTokenizer.java: New class. + * gnu/javax/security/auth/login/ConfigFileParser.java: New class. + * gnu/javax/security/auth/login/GnuConfiguration.java: New class. + * javax/security/auth/login/AppConfigurationEntry.java: Updated + copyright year. + (toString): Added method implementation. + (LoginModuleControlFlag.toString): Removed class name from result. + * javax/security/auth/login/Configuration.java: Updated copyright year. + (getConfig(): replaced calls to NullConfiguration with GnuConfiguration. + 2006-01-14 Wolfgang Baer Fixes bug #25387 Index: ConfigFileParser.java =================================================================== RCS file: ConfigFileParser.java diff -N ConfigFileParser.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ConfigFileParser.java 15 Jan 2006 05:39:16 -0000 @@ -0,0 +1,338 @@ +/* ConfigFileParser.java -- JAAS Login Configuration default syntax parser + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.login; + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.security.auth.login.AppConfigurationEntry; + +/** + * A parser that knows how to interpret JAAS Login Module Configuration files + * written in the default syntax which is interpreted as adhering to + * the following grammar: + * + *+ * CONFIG ::= APP_OR_OTHER_ENTRY+ + * APP_OR_OTHER_ENTRY ::= APP_NAME_OR_OTHER JAAS_CONFIG_BLOCK + * APP_NAME_OR_OTHER ::= APP_NAME + * | 'other' + * JAAS_CONFIG_BLOCK ::= '{' (LOGIN_MODULE_ENTRY ';')+ '}' ';' + * LOGIN_MODULE_ENTRY ::= MODULE_CLASS FLAG MODULE_OPTION* ';' + * FLAG ::= 'required' + * | 'requisite' + * | 'sufficient' + * | 'optional' + * MODULE_OPTION ::= PARAM_NAME '=' PARAM_VALUE + * + * APP_NAME ::= JAVA_IDENTIFIER + * MODULE_CLASS ::= JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)* + * PARAM_NAME ::= STRING + * PARAM_VALUE ::= '"' STRING '"' | ''' STRING ''' | STRING + *+ * + *
This parser handles UTF-8 entities when used as APP_NAME and PARAM_VALUE. + * It also checks for the use of Java identifiers used in MODULE_CLASS, thus + * minimizing the risks of having address@hidden java.lang.ClassCastException}s thrown + * at runtime due to syntactically invalid names.
+ * + *In the above context, a JAVA_IDENTIFIER is a sequence of tokens, + * separated by the character '.'. Each of these tokens obeys the following:
+ * + *true
when used as an input to
+ * the address@hidden java.lang.Character#isJavaIdentifierStart(char)}, andtrue
when used as an
+ * input to address@hidden java.lang.Character#isJavaIdentifierPart(char)}.true
if an APP_OR_OTHER_ENTRY was correctly parsed.
+ * Returns false
otherwise.
+ * @throws IOException if an exception occurs while parsing the input.
+ */
+ private boolean parseAppOrOtherEntry() throws IOException
+ {
+ int c = cft.nextToken();
+ if (c == ConfigFileTokenizer.TT_EOF)
+ return false;
+
+ if (c != ConfigFileTokenizer.TT_WORD)
+ {
+ cft.pushBack();
+ return false;
+ }
+
+ String appName = cft.sval;
+ debug("DEBUG: APP_NAME_OR_OTHER = " + appName);
+ if (cft.nextToken() != '{')
+ abort("Missing '{' after APP_NAME_OR_OTHER");
+
+ List lmis = new ArrayList();
+ while (parseACE(lmis))
+ ; // do nothing
+
+ c = cft.nextToken();
+ if (c != '}')
+ abort("Was expecting '}' but found " + (char) c);
+
+ c = cft.nextToken();
+ if (c != ';')
+ abort("Was expecting ';' but found " + (char) c);
+
+ List listOfACEs = (List) map.get(appName);
+ if (listOfACEs == null)
+ {
+ listOfACEs = new ArrayList();
+ map.put(appName, listOfACEs);
+ }
+ listOfACEs.addAll(lmis);
+ return !appName.equalsIgnoreCase("other");
+ }
+
+ /**
+ * @return true
if a LOGIN_MODULE_ENTRY was correctly parsed.
+ * Returns false
otherwise.
+ * @throws IOException if an exception occurs while parsing the input.
+ */
+ private boolean parseACE(List listOfACEs) throws IOException
+ {
+ int c = cft.nextToken();
+ if (c != ConfigFileTokenizer.TT_WORD)
+ {
+ cft.pushBack();
+ return false;
+ }
+
+ String clazz = validateClassName(cft.sval);
+ debug("DEBUG: MODULE_CLASS = " + clazz);
+
+ if (cft.nextToken() != ConfigFileTokenizer.TT_WORD)
+ abort("Was expecting FLAG but found none");
+
+ String flag = cft.sval;
+ debug("DEBUG: FLAG = " + flag);
+ AppConfigurationEntry.LoginModuleControlFlag f = null;
+ if (flag.equalsIgnoreCase("required"))
+ f = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
+ else if (flag.equalsIgnoreCase("requisite"))
+ f = AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
+ else if (flag.equalsIgnoreCase("sufficient"))
+ f = AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
+ else if (flag.equalsIgnoreCase("optional"))
+ f = AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
+ else
+ abort("Unknown Flag: " + flag);
+
+ Map options = new HashMap();
+ String paramName, paramValue;
+ c = cft.nextToken();
+ while (c != ';')
+ {
+ if (c != ConfigFileTokenizer.TT_WORD)
+ abort("Was expecting PARAM_NAME but got '" + ((char) c) + "'");
+
+ paramName = cft.sval;
+ debug("DEBUG: PARAM_NAME = " + paramName);
+ if (cft.nextToken() != '=')
+ abort("Missing '=' after PARAM_NAME");
+
+ c = cft.nextToken();
+ if (c != '"' && c != '\'')
+ debug(" WARN: Was expecting a quoted string but got no quote " +
+ "character. Assume unquoted string");
+
+ paramValue = expandParamValue(cft.sval);
+ debug("DEBUG: PARAM_VALUE = " + paramValue);
+ options.put(paramName, paramValue);
+
+ c = cft.nextToken();
+ }
+
+ AppConfigurationEntry ace = new AppConfigurationEntry(clazz, f, options);
+ debug("DEBUG: LOGIN_MODULE_ENTRY = " + ace);
+ listOfACEs.add(ace);
+ return true;
+ }
+
+ private void abort(String m) throws IOException
+ {
+ debug("ERROR: " + m);
+ debug("DEBUG: Map (so far) = " + String.valueOf(map));
+ throw new IOException(m);
+ }
+
+ private String validateClassName(String cn) throws IOException
+ {
+ if (cn.startsWith(".") || cn.endsWith("."))
+ abort("MODULE_CLASS MUST NOT start or end with a '.'");
+
+ String[] tokens = cn.split(".");
+ for (int i = 0; i < tokens.length; i++)
+ {
+ String t = tokens[i];
+ if (Character.isJavaIdentifierStart(cn.toCharArray()[0]))
+ abort("");
+
+ // we dont check the rest of the characters for isJavaIdentifierPart()
+ // because that's what the tokenizer does.
+ }
+
+ return cn;
+ }
+
+ /**
+ * The documentation of the address@hidden javax.security.auth.login.Configuration}
+ * states that: "...If a String in the form, ${system.property}, occurs in
+ * the value, it will be expanded to the value of the system property.".
+ * This method ensures this is the case. If such a string can not be expanded
+ * then it is left AS IS, assuming the LoginModule knows what to do with it.
+ *
+ * IMPORTANT: This implementation DOES NOT handle embedded ${}
+ * constructs.
+ *
+ * @param s the raw parameter value, incl. eventually strings of the form
+ * ${system.property}
.
+ * @return the input string with every occurence of
+ * ${system.property}
replaced with the value of the
+ * corresponding System property at the time of this method invocation. If
+ * the string is not a known System property name, then the complete sequence
+ * (incl. the ${} characters are passed AS IS.
+ */
+ private String expandParamValue(String s)
+ {
+ String result = s;
+ try
+ {
+ int searchNdx = 0;
+ while (searchNdx < result.length())
+ {
+ int i = s.indexOf("${", searchNdx);
+ if (i == -1)
+ break;
+
+ int j = s.indexOf("}", i + 2);
+ if (j == -1)
+ {
+ debug(" WARN: Found a ${ prefix with no } suffix. Ignore");
+ break;
+ }
+
+ String sysPropName = s.substring(i + 2, j);
+ debug("DEBUG: Found a reference to System property " + sysPropName);
+ String sysPropValue = System.getProperty(sysPropName);
+ debug("DEBUG: Resolved " + sysPropName + " to '" + sysPropValue + "'");
+ if (sysPropValue != null)
+ {
+ result = s.substring(0, i) + sysPropValue + s.substring(j + 1);
+ searchNdx = i + sysPropValue.length();
+ }
+ else
+ searchNdx = j + 1;
+ }
+ }
+ catch (Exception x)
+ {
+ debug(" WARN: Exception while expanding " + s + ". Ignore: " + x);
+ }
+
+ return result;
+ }
+}
Index: ConfigFileTokenizer.java
===================================================================
RCS file: ConfigFileTokenizer.java
diff -N ConfigFileTokenizer.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ConfigFileTokenizer.java 15 Jan 2006 05:21:15 -0000
@@ -0,0 +1,243 @@
+/* ConfigFileTokenizer.java -- JAAS Login Configuration default syntax tokenizer
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.security.auth.login;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * A UTF-8 friendly, JAAS Login Module Configuration file tokenizer written in
+ * the deault syntax. This class emulates, to a certain extent, the behavior of
+ * a address@hidden java.io.SrteamTokenizer} instance st
, when set as
+ * follows:
+ *
+ *
+ * st.resetSyntax(); + * st.lowerCaseMode(false); + * st.slashSlashComments(true); + * st.slashStarComments(true); + * st.eolIsSignificant(false); + * st.wordChars('_', '_'); + * st.wordChars('$', '$'); + * st.wordChars('A', 'Z'); + * st.wordChars('a', 'z'); + * st.wordChars('0', '9'); + * st.wordChars('.', '.'); + * st.whitespaceChars(' ', ' '); + * st.whitespaceChars('\t', '\t'); + * st.whitespaceChars('\f', '\f'); + * st.whitespaceChars('\r', '\r'); + * st.whitespaceChars('\n', '\n'); + * st.quoteChar('"'); + * st.quoteChar('\''); + *+ * + *
The most important (negative) difference with a + * address@hidden java.io.StreamTokenizer} is that this tokenizer does not properly + * handle C++ and Java // style comments in the middle of the line. It only + * ignores them if/when found at the start of the line.
+ */ +public class ConfigFileTokenizer +{ + // Constants and fields + // -------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + private static final void debug(String m) {if (DEBUG) System.err.println(m);}; + + /** A constant indicating that the end of the stream has been read. */ + public static final int TT_EOF = -1; + /** A constant indicating that a word token has been read. */ + public static final int TT_WORD = -3; + /** A constant indicating that no tokens have been read yet. */ + private static final int TT_NONE = -4; + + public String sval; + public int ttype; + + private BufferedReader br; + boolean initialised; + private StringBuffer sb; + private int sbNdx; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** Trivial constructor. */ + ConfigFileTokenizer(Reader r) + { + super(); + + br = r instanceof BufferedReader ? (BufferedReader) r : new BufferedReader(r); + initialised = false; + } + + // Class methods + // -------------------------------------------------------------------------- + + // Instance methods + // -------------------------------------------------------------------------- + + public int nextToken() throws IOException + { + if (!initialised) + init(); + + if (sbNdx >= sb.length()) + return TT_EOF; + + skipWhitespace(); + + if (sbNdx >= sb.length()) + return TT_EOF; + + int endNdx; + if (Character.isJavaIdentifierPart(sb.charAt(sbNdx))) + { + endNdx = sbNdx + 1; + while (Character.isJavaIdentifierPart(sb.charAt(endNdx)) + || sb.charAt(endNdx) == '.') + endNdx++; + + ttype = TT_WORD; + sval = sb.substring(sbNdx, endNdx); + sbNdx = endNdx; + return ttype; + } + + int c = sb.charAt(sbNdx); + if (c == '{' || c == '}' || c == ';' || c == '=') + { + ttype = c; + sbNdx++; + return ttype; + } + + if (c == '"' || c == '\'') + { + ttype = c; + String quote = sb.substring(sbNdx, sbNdx + 1); + int i = sbNdx + 1; + while (true) + { + // find a candidate + endNdx = sb.indexOf(quote, i); + if (endNdx == -1) + abort("Missing closing quote: " + quote); + + // found one; is it escaped? + if (sb.charAt(endNdx - 1) != '\\') + break; + + i++; + continue; + } + + endNdx++; + sval = sb.substring(sbNdx, endNdx); + sbNdx = endNdx; + return ttype; + } + + abort("Unknown character: " + sb.charAt(sbNdx)); + return Integer.MIN_VALUE; + } + + public void pushBack() + { + sbNdx -= ttype != TT_WORD ? 1 : sval.length(); + } + + private void init() throws IOException + { + sb = new StringBuffer(); + String line; + while ((line = br.readLine()) != null) + { + line = line.trim(); + if (line.length() == 0) + continue; + + if (line.startsWith("#") || line.startsWith("//")) + continue; + + sb.append(line).append(" "); + } + + sbNdx = 0; + sval = null; + ttype = TT_NONE; + + initialised = true; + } + + private void skipWhitespace() throws IOException + { + int endNdx; + while (sbNdx < sb.length()) + if (Character.isWhitespace(sb.charAt(sbNdx))) + { + sbNdx++; + while (sbNdx < sb.length() && Character.isWhitespace(sb.charAt(sbNdx))) + sbNdx++; + + continue; + } + else if (sb.charAt(sbNdx) == '/' && sb.charAt(sbNdx + 1) == '*') + { + endNdx = sb.indexOf("*/", sbNdx + 2); + if (endNdx == -1) + abort("Missing closing */ sequence"); + + sbNdx = endNdx + 2; + continue; + } + else + break; + } + + private void abort(String m) throws IOException + { + debug("DEBUG: " + m); + debug("DEBUG: sb = " + sb); + debug("DEBUG: sbNdx = " + sbNdx); + throw new IOException(m); + } +} Index: GnuConfiguration.java =================================================================== RCS file: GnuConfiguration.java diff -N GnuConfiguration.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ GnuConfiguration.java 15 Jan 2006 05:21:32 -0000 @@ -0,0 +1,450 @@ +/* GnuConfiguration.java -- GNU Classpath implementation of JAAS Configuration + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.login; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.Security; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.security.auth.AuthPermission; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + +/** + * An implementation of the address@hidden Configuration} class which interprets JAAS + * Login Configuration files written in the default syntax described in + * the publicly available documentation of that class. A more formal definition + * of this syntax is as follows: + * + *+ * CONFIG ::= APP_OR_OTHER_ENTRY+ + * APP_OR_OTHER_ENTRY ::= APP_NAME_OR_OTHER JAAS_CONFIG_BLOCK + * APP_NAME_OR_OTHER ::= APP_NAME + * | 'other' + * JAAS_CONFIG_BLOCK ::= '{' (LOGIN_MODULE_ENTRY ';')+ '}' ';' + * LOGIN_MODULE_ENTRY ::= MODULE_CLASS FLAG MODULE_OPTION* ';' + * FLAG ::= 'required' + * | 'requisite' + * | 'sufficient' + * | 'optional' + * MODULE_OPTION ::= PARAM_NAME '=' PARAM_VALUE + * + * APP_NAME ::= JAVA_IDENTIFIER + * MODULE_CLASS ::= JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)* + * PARAM_NAME ::= STRING + * PARAM_VALUE ::= '"' STRING '"' | ''' STRING ''' + *+ * + *
This implementation will specifically attempt to process one or more + * Login Configuration files in the following locations, and when found parse + * them and merge their contents. The locations, and the order in which they are + * investigated, follows:
+ * + *1
to an arbitrary number, are defined, then
+ * the value of each of those properties will be considered as a JAAS Login
+ * Configuration file written in the default syntax. This implementation will
+ * attempt parsing all such files.
+ *
+ * It is worth noting the following: + *
If at least one of the designated Configuration files was found, and + * was parsed correctly, then no other location will be inspected.
If this System property is defined, and the file it refers to was + * parsed correctly, then no other location will be inspected.
Configuration
.
+ *
+ * This method causes this Configuration
object to refresh /
+ * reload its contents following the locations and logic described above in
+ * the class documentation section.
refreshLoginConfiguration
.
+ * @see address@hidden AuthPermission}
+ */
+ public void refresh()
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new AuthPermission("refreshLoginConfiguration"));
+
+ loginModulesMap.clear();
+ init();
+ }
+
+ // helper methods -----------------------------------------------------------
+
+ /**
+ * Attempts to find and parse JAAS Login Configuration file(s) written in
+ * the default syntax. The locations searched are as descibed in the class
+ * documentation.
+ */
+ private void init()
+ {
+ if (processSecurityProperties())
+ debug(" INFO: Using login configuration defined by Security property(ies)");
+ else if (processSystemProperty())
+ debug(" INFO: Using login configuration defined by System property");
+ else if (processUserHome())
+ debug(" INFO: Using login configuration defined in ${user.home}");
+ else
+ debug(" WARN: No login configuration file found");
+ }
+
+ /**
+ * Attempts to locate and parse one or more JAAS Login Configuration files
+ * defined as the values of the Security properties
+ * java.security.auth.login.config.url.N.
+ *
+ * @return true
if it succeeds, and false
+ * otherwsie.
+ */
+ private boolean processSecurityProperties()
+ {
+ boolean result = false;
+ int counter = 0;
+ String s;
+ while (true)
+ try
+ {
+ counter++;
+ s = Security.getProperty("java.security.auth.login.config.url."
+ + counter);
+ if (s == null)
+ break;
+
+ s = s.trim();
+ if (s.length() != 0)
+ {
+ debug("DEBUG: java.security.auth.login.config.url." + counter
+ + " = " + s);
+ parseConfig(getInputStreamFromURL(s));
+ result = true;
+ }
+ }
+ catch (Throwable t)
+ {
+ debug(" WARN: Exception while handling Security property at #"
+ + counter + ". Continue: " + t);
+ }
+ return result;
+ }
+
+ /**
+ * Attempts to open a designated string as a well-formed address@hidden URL}. If a
+ * address@hidden MalformedURLException} occurs, this method then tries to open that
+ * string as a address@hidden File} (with the same name). If it succeeds, an
+ * address@hidden InputStream} is constructed and returned.
+ *
+ * @param s
+ * the designated name of either a address@hidden URL} or a address@hidden File}
+ * assumed to contain a JAAS Login Configuration in the default
+ * syntax.
+ * @return an address@hidden InputStream} around the data source.
+ * @throws IOException
+ * if an exception occurs during the operation.
+ */
+ private InputStream getInputStreamFromURL(String s) throws IOException
+ {
+ InputStream result = null;
+ try
+ {
+ URL url = new URL(s);
+ result = url.openStream();
+ }
+ catch (MalformedURLException x)
+ {
+ debug(" WARN: Failed opening as URL: " + s + ". Will try as File");
+ result = new FileInputStream(s);
+ }
+ return result;
+ }
+
+ /**
+ * Attempts to locate and parse a JAAS Login Configuration file defined as the
+ * value of the System property java.security.auth.login.config.
+ *
+ * @return true
if it succeeds, and false
+ * otherwsie.
+ */
+ private boolean processSystemProperty()
+ {
+ boolean result = false;
+ try
+ {
+ String s = System.getProperty("java.security.auth.login.config");
+ if (s != null)
+ {
+ s = s.trim();
+ if (s.length() != 0)
+ {
+ debug("DEBUG: java.security.auth.login.config = " + s);
+ parseConfig(getInputStreamFromURL(s));
+ result = true;
+ }
+ }
+ }
+ catch (Throwable t)
+ {
+ debug(" WARN: Exception while handling System property. Continue: " + t);
+ }
+ return result;
+ }
+
+ /**
+ * Attempts to locate and parse a JAAS Login Configuration file named either
+ * as .java.login.config or java.login.config (without the
+ * leading dot) in the folder referenced by the System property
+ * user.home
.
+ *
+ * @return true
if it succeeds, and false
+ * otherwsie.
+ */
+ private boolean processUserHome()
+ {
+ boolean result = false;
+ try
+ {
+ File userHome = getUserHome();
+ if (userHome == null)
+ return result;
+
+ File jaasFile;
+ jaasFile = getConfigFromUserHome(userHome, ".java.login.config");
+ if (jaasFile == null)
+ jaasFile = getConfigFromUserHome(userHome, "java.login.config");
+
+ if (jaasFile == null)
+ {
+ debug(" WARN: Login Configuration file, in " + userHome
+ + ", does not exist or is inaccessible");
+ return result;
+ }
+
+ FileInputStream fis = new FileInputStream(jaasFile);
+ parseConfig(fis);
+ result = true;
+ }
+ catch (Throwable t)
+ {
+ debug(" WARN: Exception while handling ${user.home}: " + t);
+ }
+ return result;
+ }
+
+ private void parseConfig(InputStream configStream) throws IOException
+ {
+ cp.parse(new InputStreamReader(configStream, "UTF-8"));
+ Map loginModulesMap = cp.getLoginModulesMap();
+ mergeLoginModules(loginModulesMap);
+ }
+
+ private void mergeLoginModules(Map otherLoginModules)
+ {
+ if (otherLoginModules == null || otherLoginModules.size() < 1)
+ return;
+
+ for (Iterator it = otherLoginModules.keySet().iterator(); it.hasNext();)
+ {
+ String appName = (String) it.next();
+ List thatListOfACEs = (List) otherLoginModules.get(appName);
+ if (thatListOfACEs == null || thatListOfACEs.size() < 1)
+ continue;
+
+ List thisListsOfACEs = (List) loginModulesMap.get(appName);
+ if (thisListsOfACEs == null)
+ loginModulesMap.put(appName, thatListOfACEs);
+ else
+ thisListsOfACEs.addAll(thatListOfACEs);
+ }
+ }
+
+ private File getUserHome()
+ {
+ String uh = System.getProperty("user.home");
+ if (uh == null || uh.trim().length() == 0)
+ {
+ debug(" WARN: User home path is not set or is empty");
+ return null;
+ }
+
+ uh = uh.trim();
+ File result = new File(uh);
+ if (!result.exists())
+ {
+ debug(" WARN: User home '" + uh + "' does not exist");
+ return null;
+ }
+
+ if (!result.isDirectory())
+ {
+ debug(" WARN: User home '" + uh + "' is not a directory");
+ return null;
+ }
+
+ if (!result.canRead())
+ {
+ debug(" WARN: User home '" + uh + "' is not readable");
+ return null;
+ }
+
+ return result;
+ }
+
+ private File getConfigFromUserHome(File userHome, String fileName)
+ {
+ File result = new File(userHome, fileName);
+ if (!result.exists())
+ {
+ debug(" WARN: File '" + fileName + "' does not exist in user's home");
+ return null;
+ }
+
+ if (!result.isFile())
+ {
+ debug(" WARN: File '" + fileName + "' in user's home is not a file");
+ return null;
+ }
+
+ if (!result.canRead())
+ {
+ debug(" WARN: File '" + fileName + "' in user's home is not readable");
+ return null;
+ }
+
+ return result;
+ }
+}
Index: AppConfigurationEntry.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/security/auth/login/AppConfigurationEntry.java,v
retrieving revision 1.2
diff -u -r1.2 AppConfigurationEntry.java
--- AppConfigurationEntry.java 2 Jul 2005 20:32:46 -0000 1.2
+++ AppConfigurationEntry.java 15 Jan 2006 05:21:58 -0000
@@ -1,5 +1,5 @@
/* AppConfigurationEntry.java
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -44,7 +44,6 @@
public class AppConfigurationEntry
{
-
// Fields.
// -------------------------------------------------------------------------
@@ -61,13 +60,16 @@
{
if (loginModuleName == null || loginModuleName.length() == 0)
throw new IllegalArgumentException ("module name cannot be null nor empty");
+
if (LoginModuleControlFlag.OPTIONAL != controlFlag &&
LoginModuleControlFlag.REQUIRED != controlFlag &&
LoginModuleControlFlag.REQUISITE != controlFlag &&
LoginModuleControlFlag.SUFFICIENT != controlFlag)
throw new IllegalArgumentException ("invalid controlFlag");
+
if (options == null)
throw new IllegalArgumentException ("options cannot be null");
+
this.loginModuleName = loginModuleName;
this.controlFlag = controlFlag;
this.options = Collections.unmodifiableMap (new HashMap (options));
@@ -91,7 +93,17 @@
return options;
}
-// Inner class.
+ // Object methods ----------------------------------------------------------
+
+ public String toString()
+ {
+
+ return loginModuleName + "\t"
+ + String.valueOf(controlFlag) + "\t"
+ + String.valueOf(options);
+ }
+
+ // Inner class.
// -------------------------------------------------------------------------
public static class LoginModuleControlFlag
@@ -117,19 +129,15 @@
public String toString()
{
- StringBuffer buf = new StringBuffer (LoginModuleControlFlag.class.getName());
- buf.append ('.');
- if (this == OPTIONAL)
- buf.append ("OPTIONAL");
- else if (this == REQUIRED)
- buf.append ("REQUIRED");
- else if (this == REQUISITE)
- buf.append ("REQUISITE");
- else if (this == SUFFICIENT)
- buf.append ("SUFFICIENT");
- else
- buf.append ("HARVEY_THE_RABBIT");
- return buf.toString();
+ if (this == LoginModuleControlFlag.REQUIRED)
+ return "REQUIRED";
+ if (this == LoginModuleControlFlag.REQUISITE)
+ return "REQUISITE";
+ if (this == LoginModuleControlFlag.SUFFICIENT)
+ return "SUFFICIENT";
+ if (this == LoginModuleControlFlag.OPTIONAL)
+ return "OPTIONAL";
+ return "???";
}
}
}
Index: Configuration.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/security/auth/login/Configuration.java,v
retrieving revision 1.4
diff -u -r1.4 Configuration.java
--- Configuration.java 9 Sep 2005 12:17:30 -0000 1.4
+++ Configuration.java 15 Jan 2006 05:22:14 -0000
@@ -1,5 +1,5 @@
/* Configuration.java
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,8 @@
package javax.security.auth.login;
+import gnu.javax.security.auth.login.GnuConfiguration;
+
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.Security;
@@ -46,7 +48,6 @@
public abstract class Configuration
{
-
// Fields.
// -------------------------------------------------------------------------
@@ -108,11 +109,11 @@
if (conf != null)
config = (Configuration) Class.forName (conf).newInstance();
else
- config = new NullConfiguration();
+ config = new GnuConfiguration();
}
catch (Exception x)
{
- config = new NullConfiguration();
+ config = new GnuConfiguration();
}
}
return config;