summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu/javax/security/auth/login
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/gnu/javax/security/auth/login
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libjava/classpath/gnu/javax/security/auth/login')
-rw-r--r--libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java346
-rw-r--r--libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java246
-rw-r--r--libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java466
3 files changed, 1058 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java
new file mode 100644
index 000000000..5c4c4261f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java
@@ -0,0 +1,346 @@
+/* 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 gnu.java.security.Configuration;
+
+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 java.util.logging.Logger;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+/**
+ * A parser that knows how to interpret JAAS Login Module Configuration files
+ * written in the <i>default syntax</i> which is interpreted as adhering to
+ * the following grammar:
+ *
+ * <pre>
+ * 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
+ * </pre>
+ *
+ * <p>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 {@link java.lang.ClassCastException}s thrown
+ * at runtime due to syntactically invalid names.</p>
+ *
+ * <p>In the above context, a JAVA_IDENTIFIER is a sequence of tokens,
+ * separated by the character '.'. Each of these tokens obeys the following:</p>
+ *
+ * <ol>
+ * <li>its first character yields <code>true</code> when used as an input to
+ * the {@link java.lang.Character#isJavaIdentifierStart(char)}, and</li>
+ * <li>all remaining characters, yield <code>true</code> when used as an
+ * input to {@link java.lang.Character#isJavaIdentifierPart(char)}.</li>
+ * </ol>
+ */
+public final class ConfigFileParser
+{
+ private static final Logger log = Logger.getLogger(ConfigFileParser.class.getName());
+ private ConfigFileTokenizer cft;
+ private Map map = new HashMap();
+
+ // default 0-arguments constructor
+
+ /**
+ * Returns the parse result as a {@link Map} where the keys are application
+ * names, and the entries are {@link List}s of {@link AppConfigurationEntry}
+ * entries, one for each login module entry, in the order they were
+ * encountered, for that application name in the just parsed configuration
+ * file.
+ */
+ public Map getLoginModulesMap()
+ {
+ return map;
+ }
+
+ /**
+ * Parses the {@link Reader}'s contents assuming it is in the <i>default
+ * syntax</i>.
+ *
+ * @param r the {@link Reader} whose contents are assumed to be a JAAS Login
+ * Configuration Module file written in the <i>default syntax</i>.
+ * @throws IOException if an exception occurs while parsing the input.
+ */
+ public void parse(Reader r) throws IOException
+ {
+ initParser(r);
+
+ while (parseAppOrOtherEntry())
+ {
+ /* do nothing */
+ }
+ }
+
+ private void initParser(Reader r) throws IOException
+ {
+ map.clear();
+
+ cft = new ConfigFileTokenizer(r);
+ }
+
+ /**
+ * @return <code>true</code> if an APP_OR_OTHER_ENTRY was correctly parsed.
+ * Returns <code>false</code> 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;
+ if (Configuration.DEBUG)
+ log.fine("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 <code>true</code> if a LOGIN_MODULE_ENTRY was correctly parsed.
+ * Returns <code>false</code> 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);
+ if (Configuration.DEBUG)
+ log.fine("MODULE_CLASS = " + clazz);
+
+ if (cft.nextToken() != ConfigFileTokenizer.TT_WORD)
+ abort("Was expecting FLAG but found none");
+
+ String flag = cft.sval;
+ if (Configuration.DEBUG)
+ log.fine("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;
+ if (Configuration.DEBUG)
+ log.fine("PARAM_NAME = " + paramName);
+ if (cft.nextToken() != '=')
+ abort("Missing '=' after PARAM_NAME");
+
+ c = cft.nextToken();
+ if (c != '"' && c != '\'')
+ {
+ if (Configuration.DEBUG)
+ log.fine("Was expecting a quoted string but got no quote character."
+ + " Assume unquoted string");
+ }
+ paramValue = expandParamValue(cft.sval);
+ if (Configuration.DEBUG)
+ log.fine("PARAM_VALUE = " + paramValue);
+ options.put(paramName, paramValue);
+
+ c = cft.nextToken();
+ }
+ AppConfigurationEntry ace = new AppConfigurationEntry(clazz, f, options);
+ if (Configuration.DEBUG)
+ log.fine("LOGIN_MODULE_ENTRY = " + ace);
+ listOfACEs.add(ace);
+ return true;
+ }
+
+ private void abort(String m) throws IOException
+ {
+ if (Configuration.DEBUG)
+ {
+ log.fine(m);
+ log.fine("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(t.charAt(0)))
+ abort("Class name [" + cn
+ + "] contains an invalid sub-package identifier: " + t);
+
+ // we dont check the rest of the characters for isJavaIdentifierPart()
+ // because that's what the tokenizer does.
+ }
+
+ return cn;
+ }
+
+ /**
+ * The documentation of the {@link javax.security.auth.login.Configuration}
+ * states that: <i>"...If a String in the form, ${system.property}, occurs in
+ * the value, it will be expanded to the value of the system property."</i>.
+ * 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.
+ *
+ * <p><b>IMPORTANT</b>: This implementation DOES NOT handle embedded ${}
+ * constructs.
+ *
+ * @param s the raw parameter value, incl. eventually strings of the form
+ * <code>${system.property}</code>.
+ * @return the input string with every occurence of
+ * <code>${system.property}</code> 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)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Found a ${ prefix with no } suffix. Ignore");
+ break;
+ }
+
+ String sysPropName = s.substring(i + 2, j);
+ if (Configuration.DEBUG)
+ log.fine("Found a reference to System property " + sysPropName);
+ String sysPropValue = System.getProperty(sysPropName);
+ if (Configuration.DEBUG)
+ log.fine("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)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Exception (ignored) while expanding " + s + ": " + x);
+ }
+
+ return result;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java
new file mode 100644
index 000000000..fc35bf772
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java
@@ -0,0 +1,246 @@
+/* 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 gnu.java.lang.CPStringBuilder;
+
+import gnu.java.security.Configuration;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.logging.Logger;
+
+/**
+ * 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 {@link java.io.StreamTokenizer} instance <code>st</code>, when set as
+ * follows:
+ *
+ * <pre>
+ * 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('\'');
+ * </pre>
+ *
+ * <p>The most important (negative) difference with a
+ * {@link 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.</p>
+ */
+public class ConfigFileTokenizer
+{
+ private static final Logger log = Logger.getLogger(ConfigFileParser.class.getName());
+ /** 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 CPStringBuilder 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 CPStringBuilder();
+ 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
+ {
+ if (Configuration.DEBUG)
+ {
+ log.fine(m);
+ log.fine("sb = " + sb);
+ log.fine("sbNdx = " + sbNdx);
+ }
+ throw new IOException(m);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java b/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java
new file mode 100644
index 000000000..20d8f3afd
--- /dev/null
+++ b/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java
@@ -0,0 +1,466 @@
+/* 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 java.util.logging.Logger;
+
+import javax.security.auth.AuthPermission;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+/**
+ * An implementation of the {@link Configuration} class which interprets JAAS
+ * Login Configuration files written in the <i>default</i> syntax described in
+ * the publicly available documentation of that class. A more formal definition
+ * of this syntax is as follows:
+ *
+ * <pre>
+ * 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
+ * </pre>
+ *
+ * <p>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:</p>
+ *
+ * <ol>
+ * <li>If the following Security properties:
+ * <i>java.security.auth.login.config.url.<b>N</b></i>, where <i><b>N</b></i>
+ * is a digit, from <code>1</code> 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.
+ *
+ * <p>It is worth noting the following:
+ * <ul>
+ * <li>The GNU Classpath security file, named <i>classpath.security</i>,
+ * where all Security properties are encoded, is usually located in
+ * <i>/usr/local/classpath/lib/security</i> folder.</li>
+ *
+ * <li>The numbers used in the properties
+ * <i>java.security.auth.login.config.url.<b>N</b></i> MUST be sequential,
+ * with no breaks in-between.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>If at least one of the designated Configuration files was found, and
+ * was parsed correctly, then no other location will be inspected.</p></li>
+ *
+ * <li>If the System property named <i>java.security.auth.login.config</i>
+ * is not null or empty, its contents are then interpreted as a URL to a
+ * JAAS Login Configuration file written in the default syntax.
+ *
+ * <p>If this System property is defined, and the file it refers to was
+ * parsed correctly, then no other location will be inspected.</p></li>
+ *
+ * <li>If a file named <i>.java.login.config</i> or <i>java.login.config</i>
+ * (in that order) is found in the location referenced by the value of the
+ * System property <i>user.home</i>, then that file is parsed as a JAAS Login
+ * Configuration written in the default syntax.</li>
+ *
+ * <li>If none of the above resulted in a correctly parsed JAAS Login
+ * Configuration file, then this implementation will install a <i>Null
+ * Configuration</i> which basically does not recognize any Application.</li>
+ * </ol>
+ */
+public final class GnuConfiguration extends Configuration
+{
+ private static final Logger log = Logger.getLogger(GnuConfiguration.class.getName());
+ /**
+ * The internal map of login modules keyed by application name. Each entry in
+ * this map is a {@link List} of {@link AppConfigurationEntry}s for that
+ * application name.
+ */
+ private Map loginModulesMap;
+ /** Our reference to our default syntax parser. */
+ private ConfigFileParser cp;
+
+ // Constructor(s)
+ // --------------------------------------------------------------------------
+
+ /** Trivial 0-arguments Constructor. */
+ public GnuConfiguration()
+ {
+ super();
+
+ loginModulesMap = new HashMap();
+ cp = new ConfigFileParser();
+ init();
+ }
+
+ // Class methods
+ // --------------------------------------------------------------------------
+
+ // Instance methods
+ // --------------------------------------------------------------------------
+
+ // Configuration abstract methods implementation ----------------------------
+
+ /* (non-Javadoc)
+ * @see javax.security.auth.login.Configuration#getAppConfigurationEntry(java.lang.String)
+ */
+ public AppConfigurationEntry[] getAppConfigurationEntry(String appName)
+ {
+ if (appName == null)
+ return null;
+
+ appName = appName.trim();
+ if (appName.length() == 0)
+ return null;
+
+ List loginModules = (List) loginModulesMap.get(appName);
+ if (loginModules == null || loginModules.size() == 0)
+ return null;
+
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine(appName + " -> " + loginModules.size() + " entry(ies)");
+ return (AppConfigurationEntry[]) loginModules.toArray(new AppConfigurationEntry[0]);
+ }
+
+ /**
+ * Refreshes and reloads this <code>Configuration</code>.
+ *
+ * <p>This method causes this <code>Configuration</code> object to refresh /
+ * reload its contents following the locations and logic described above in
+ * the class documentation section.</p>
+ *
+ * @throws SecurityException if the caller does not have an
+ * {@link AuthPermission} for the action named
+ * <code>refreshLoginConfiguration</code>.
+ * @see 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())
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("Using login configuration defined by Security property(ies)");
+ }
+ else if (processSystemProperty())
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("Using login configuration defined by System property");
+ }
+ else if (processUserHome())
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("Using login configuration defined in ${user.home}");
+ }
+ else
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("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
+ * <i>java.security.auth.login.config.url.N</i>.
+ *
+ * @return <code>true</code> if it succeeds, and <code>false</code>
+ * 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)
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("java.security.auth.login.config.url." + counter
+ + " = " + s);
+ parseConfig(getInputStreamFromURL(s));
+ result = true;
+ }
+ }
+ catch (Throwable t)
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("Exception while handling Security property at #"
+ + counter + ". Continue: " + t);
+ }
+ return result;
+ }
+
+ /**
+ * Attempts to open a designated string as a well-formed {@link URL}. If a
+ * {@link MalformedURLException} occurs, this method then tries to open that
+ * string as a {@link File} (with the same name). If it succeeds, an
+ * {@link InputStream} is constructed and returned.
+ *
+ * @param s
+ * the designated name of either a {@link URL} or a {@link File}
+ * assumed to contain a JAAS Login Configuration in the default
+ * syntax.
+ * @return an {@link 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)
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("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 <i>java.security.auth.login.config</i>.
+ *
+ * @return <code>true</code> if it succeeds, and <code>false</code>
+ * 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)
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("java.security.auth.login.config = " + s);
+ parseConfig(getInputStreamFromURL(s));
+ result = true;
+ }
+ }
+ }
+ catch (Throwable t)
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("Exception while handling System property. Continue: " + t);
+ }
+ return result;
+ }
+
+ /**
+ * Attempts to locate and parse a JAAS Login Configuration file named either
+ * as <i>.java.login.config</i> or <i>java.login.config</i> (without the
+ * leading dot) in the folder referenced by the System property
+ * <code>user.home</code>.
+ *
+ * @return <code>true</code> if it succeeds, and <code>false</code>
+ * 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)
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("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)
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("Exception (ignored) 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)
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("User home path is not set or is empty");
+ return null;
+ }
+ uh = uh.trim();
+ File result = new File(uh);
+ if (! result.exists())
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("User home '" + uh + "' does not exist");
+ return null;
+ }
+ if (! result.isDirectory())
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("User home '" + uh + "' is not a directory");
+ return null;
+ }
+ if (! result.canRead())
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("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())
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("File '" + fileName + "' does not exist in user's home");
+ return null;
+ }
+ if (! result.isFile())
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("File '" + fileName + "' in user's home is not a file");
+ return null;
+ }
+ if (! result.canRead())
+ {
+ if (gnu.java.security.Configuration.DEBUG)
+ log.fine("File '" + fileName + "' in user's home is not readable");
+ return null;
+ }
+ return result;
+ }
+}