From 8504c8ad52d38b2cece465e5ab0013c9aca234e6 Mon Sep 17 00:00:00 2001 From: weijun Date: Mon, 29 Oct 2012 14:14:06 +0800 Subject: [PATCH] 7184246: Simplify Config.get() of krb5 Reviewed-by: xuelei --- .../classes/sun/security/krb5/Checksum.java | 12 +- .../classes/sun/security/krb5/Config.java | 701 +++++++----------- .../classes/sun/security/krb5/KdcComm.java | 8 +- .../sun/security/krb5/PrincipalName.java | 6 +- .../classes/sun/security/krb5/Realm.java | 4 +- .../security/krb5/SCDynamicStoreConfig.java | 68 +- .../security/krb5/internal/KDCOptions.java | 16 +- .../security/krb5/internal/KerberosTime.java | 6 +- .../krb5/internal/crypto/CksumType.java | 8 +- .../security/krb5/internal/crypto/EType.java | 12 +- .../security/krb5/internal/ktab/KeyTab.java | 4 +- test/sun/security/krb5/ConfPlusProp.java | 9 +- test/sun/security/krb5/DnsFallback.java | 37 +- test/sun/security/krb5/ParseConfig.java | 3 +- .../sun/security/krb5/auto/BasicKrb5Test.java | 3 +- test/sun/security/krb5/auto/MaxRetries.java | 2 +- test/sun/security/krb5/config/Duplicates.java | 72 ++ .../krb5/config/SCDynamicConfigTest.java | 102 +++ test/sun/security/krb5/config/k1.conf | 40 + 19 files changed, 589 insertions(+), 524 deletions(-) create mode 100644 test/sun/security/krb5/config/Duplicates.java create mode 100644 test/sun/security/krb5/config/SCDynamicConfigTest.java create mode 100644 test/sun/security/krb5/config/k1.conf diff --git a/src/share/classes/sun/security/krb5/Checksum.java b/src/share/classes/sun/security/krb5/Checksum.java index 4cc582049..54155a39b 100644 --- a/src/share/classes/sun/security/krb5/Checksum.java +++ b/src/share/classes/sun/security/krb5/Checksum.java @@ -74,14 +74,18 @@ public class Checksum { private static boolean DEBUG = Krb5.DEBUG; static { + initStatic(); + } + + public static void initStatic() { String temp = null; Config cfg = null; try { cfg = Config.getInstance(); - temp = cfg.getDefault("default_checksum", "libdefaults"); + temp = cfg.get("libdefaults", "default_checksum"); if (temp != null) { - CKSUMTYPE_DEFAULT = cfg.getType(temp); + CKSUMTYPE_DEFAULT = Config.getType(temp); } else { /* * If the default checksum is not @@ -103,10 +107,10 @@ public class Checksum { try { - temp = cfg.getDefault("safe_checksum_type", "libdefaults"); + temp = cfg.get("libdefaults", "safe_checksum_type"); if (temp != null) { - SAFECKSUMTYPE_DEFAULT = cfg.getType(temp); + SAFECKSUMTYPE_DEFAULT = Config.getType(temp); } else { SAFECKSUMTYPE_DEFAULT = CKSUMTYPE_RSA_MD5_DES; } diff --git a/src/share/classes/sun/security/krb5/Config.java b/src/share/classes/sun/security/krb5/Config.java index 596fa80a0..486f59f2e 100644 --- a/src/share/classes/sun/security/krb5/Config.java +++ b/src/share/classes/sun/security/krb5/Config.java @@ -38,11 +38,14 @@ import java.util.ArrayList; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; -import java.util.Enumeration; import java.util.StringTokenizer; import java.net.InetAddress; import java.net.UnknownHostException; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; +import java.util.Arrays; import java.util.List; +import java.util.Locale; import sun.net.dns.ResolverConfiguration; import sun.security.krb5.internal.crypto.EType; import sun.security.krb5.internal.Krb5; @@ -62,7 +65,7 @@ public class Config { /* * Hashtable used to store configuration infomation. */ - private Hashtable stanzaTable; + private Hashtable stanzaTable = new Hashtable<>(); private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; @@ -100,7 +103,9 @@ public class Config { /** * Refresh and reload the Configuration. This could involve, * for example reading the Configuration file again or getting - * the java.security.krb5.* system properties again. + * the java.security.krb5.* system properties again. This method + * also tries its best to update static fields in other classes + * that depend on the configuration. * * @exception KrbException if error occurs when constructing a Config * instance. Possible causes would be either of java.security.krb5.realm or @@ -110,6 +115,8 @@ public class Config { public static synchronized void refresh() throws KrbException { singleton = new Config(); KdcComm.initStatic(); + EType.initStatic(); + Checksum.initStatic(); } @@ -163,7 +170,7 @@ public class Config { // Always read the Kerberos configuration file try { - Vector configFile; + List configFile; String fileName = getJavaFileName(); if (fileName != null) { configFile = loadConfigFile(fileName); @@ -194,61 +201,93 @@ public class Config { } } } catch (IOException ioe) { - // No krb5.conf, no problem. We'll use DNS or system property etc. + // I/O error, mostly like krb5.conf missing. + // No problem. We'll use DNS or system property etc. } } /** - * Gets the default int value for the specified name. - * @param name the name. - * @return the default Integer, null is returned if no such name and - * value are found in configuration file, or error occurs when parsing - * string to integer. + * Gets the last-defined string value for the specified keys. + * @param keys the keys, as an array from section name, sub-section names + * (if any), to value name. + * @return the value. When there are multiple values for the same key, + * returns the last one. {@code null} is returned if not all the keys are + * defined. For example, {@code get("libdefaults", "forwardable")} will + * return null if "forwardable" is not defined in [libdefaults], and + * {@code get("realms", "R", "kdc")} will return null if "R" is not + * defined in [realms] or "kdc" is not defined for "R". + * @throws IllegalArgumentException if any of the keys is illegal, either + * because a key not the last one is not a (sub)section name or the last + * key is still a section name. For example, {@code get("libdefaults")} + * throws this exception because [libdefaults] is a section name instead of + * a value name, and {@code get("libdefaults", "forwardable", "tail")} + * also throws this exception because "forwardable" is already a value name + * and has no sub-key at all (given "forwardable" is defined, otherwise, + * this method has no knowledge if it's a value name or a section name), */ - public int getDefaultIntValue(String name) { - String result = null; - int value = Integer.MIN_VALUE; - result = getDefault(name); - if (result != null) { - try { - value = parseIntValue(result); - } catch (NumberFormatException e) { - if (DEBUG) { - System.out.println("Exception in getting value of " + - name + " " + - e.getMessage()); - System.out.println("Setting " + name + - " to minimum value"); - } - value = Integer.MIN_VALUE; + @SuppressWarnings("unchecked") + public String get(String... keys) { + Vector v = get0(keys); + if (v == null) return null; + return v.lastElement(); + } + + /** + * Gets all values for the specified keys. + * @see #get(java.lang.String[]) + */ + public String getAll(String... keys) { + Vector v = get0(keys); + if (v == null) return null; + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (String s: v) { + if (first) { + sb.append(s); + first = false; + } else { + sb.append(' ').append(s); } } - return value; + return sb.toString(); + } + + // Internal method. Returns the vector of strings for keys. + // The only method (except for toString) that reads stanzaTable directly. + @SuppressWarnings("unchecked") + private Vector get0(String... keys) { + Object current = stanzaTable; + try { + for (String key: keys) { + current = ((Hashtable)current).get(key); + if (current == null) return null; + } + return (Vector)current; + } catch (ClassCastException cce) { + throw new IllegalArgumentException(cce); + } } /** - * Gets the default int value for the specified name in the specified - * section.
This method is quicker by using section name as the - * search key. - * @param name the name. - * @param sectio the name string of the section. - * @return the default Integer, null is returned if no such name and - * value are found in configuration file, or error occurs when parsing - * string to integer. + * Gets the int value for the specified keys. + * @param keys the keys + * @return the int value, Integer.MIN_VALUE is returned if it cannot be + * found or the value is not a legal integer. + * @throw IllegalArgumentException if any of the keys is illegal + * @see #get(java.lang.String[]) */ - public int getDefaultIntValue(String name, String section) { - String result = null; + public int getIntValue(String... keys) { + String result = get(keys); int value = Integer.MIN_VALUE; - result = getDefault(name, section); if (result != null) { try { value = parseIntValue(result); } catch (NumberFormatException e) { if (DEBUG) { System.out.println("Exception in getting value of " + - name +" in section " + - section + " " + e.getMessage()); - System.out.println("Setting " + name + + Arrays.toString(keys) + " " + + e.getMessage()); + System.out.println("Setting " + Arrays.toString(keys) + " to minimum value"); } value = Integer.MIN_VALUE; @@ -258,152 +297,15 @@ public class Config { } /** - * Gets the default string value for the specified name. - * @param name the name. - * @return the default value, null is returned if it cannot be found. - */ - public String getDefault(String name) { - if (stanzaTable == null) { - return null; - } else { - return getDefault(name, stanzaTable); - } - } - - /** - * This method does the real job to recursively search through the - * stanzaTable. - * @param k the key string. - * @param t stanzaTable or sub hashtable within it. - * @return the value found in config file, returns null if no value - * matched with the key is found. - */ - private String getDefault(String k, Hashtable t) { - String result = null; - String key; - if (stanzaTable != null) { - for (Enumeration e = t.keys(); e.hasMoreElements(); ) { - key = e.nextElement(); - Object ob = t.get(key); - if (ob instanceof Hashtable) { - @SuppressWarnings("unchecked") // Checked with an instanceof check - Hashtable table = - (Hashtable)ob; - result = getDefault(k, table); - if (result != null) { - return result; - } - } else if (key.equalsIgnoreCase(k)) { - if (ob instanceof String) { - return (String)(t.get(key)); - } else if (ob instanceof Vector) { - result = ""; - int length = ((Vector)ob).size(); - for (int i = 0; i < length; i++) { - if (i == length -1) { - result += - (String)(((Vector)ob).elementAt(i)); - } else { - result += - (String)(((Vector)ob).elementAt(i)) + " "; - } - } - return result; - } - } - } - } - return result; - } - - /** - * Gets the default string value for the specified name in the - * specified section. - *
This method is quicker by using the section name as the search key. - * @param name the name. - * @param section the name of the section. - * @return the default value, null is returned if it cannot be found. + * Gets the boolean value for the specified keys. + * @param keys the keys + * @return the boolean value, false is returned if it cannot be + * found or the value is not "true" (case insensitive). + * @throw IllegalArgumentException if any of the keys is illegal + * @see #get(java.lang.String[]) */ - // stanzaTable leads to a lot of unchecked casts since its value type is - // STANZATABLE = String | Hashtable - @SuppressWarnings("unchecked") - public String getDefault(String name, String section) { - String stanzaName; - String result = null; - Hashtable subTable; - - if (stanzaTable != null) { - for (Enumeration e = stanzaTable.keys(); - e.hasMoreElements(); ) { - stanzaName = e.nextElement(); - subTable = (Hashtable) - stanzaTable.get(stanzaName); - if (stanzaName.equalsIgnoreCase(section)) { - if (subTable.containsKey(name)) { - return (String)(subTable.get(name)); - } - } else if (subTable.containsKey(section)) { - Object ob = subTable.get(section); - if (ob instanceof Hashtable) { - Hashtable temp = - (Hashtable)ob; - if (temp.containsKey(name)) { - Object object = temp.get(name); - if (object instanceof Vector) { - result = ""; - int length = ((Vector)object).size(); - for (int i = 0; i < length; i++) { - if (i == length - 1) { - result += - (String)(((Vector)object).elementAt(i)); - } else { - result += - (String)(((Vector)object).elementAt(i)) - + " "; - } - } - } else { - result = (String)object; - } - } - } - } - } - } - return result; - } - - /** - * Gets the default boolean value for the specified name. - * @param name the name. - * @return the default boolean value, false is returned if it cannot be - * found. - */ - public boolean getDefaultBooleanValue(String name) { - String val = null; - if (stanzaTable == null) { - val = null; - } else { - val = getDefault(name, stanzaTable); - } - if (val != null && val.equalsIgnoreCase("true")) { - return true; - } else { - return false; - } - } - - /** - * Gets the default boolean value for the specified name in the - * specified section. - *
This method is quicker by using the section name as the search key. - * @param name the name. - * @param section the name of the section. - * @return the default boolean value, false is returned if it cannot be - * found. - */ - public boolean getDefaultBooleanValue(String name, String section) { - String val = getDefault(name, section); + public boolean getBooleanValue(String... keys) { + String val = get(keys); if (val != null && val.equalsIgnoreCase("true")) { return true; } else { @@ -528,29 +430,14 @@ public class Config { } /** - * Finds the matching value in the hashtable. - */ - private String find(String key1, String key2) { - String result; - if ((stanzaTable != null) && - ((result = (String) - (((Hashtable)(stanzaTable.get(key1))).get(key2))) != null)) { - return result; - } else { - return ""; - } - } - - /** - * Reads name/value pairs to the memory from the configuration - * file. The default location of the configuration file is in java home - * directory. + * Reads lines to the memory from the configuration file. * * Configuration file contains information about the default realm, * ticket parameters, location of the KDC and the admin server for * known realms, etc. The file is divided into sections. Each section * contains one or more name/value pairs with one pair per line. A * typical file would be: + *
      * [libdefaults]
      *          default_realm = EXAMPLE.COM
      *          default_tgs_enctypes = des-cbc-md5
@@ -568,128 +455,178 @@ public class Config {
      * [domain_realm]
      *          blue.sample.com = TEST.SAMPLE.COM
      *          .backup.com     = EXAMPLE.COM
-     *
-     * @params fileName the conf file, cannot be null
-     * @return the content, null if fileName is empty
-     * @throws IOException if there is an I/O or format error
+     * 
+ * @return an ordered list of strings representing the config file after + * some initial processing, including:
    + *
  1. Comment lines and empty lines are removed + *
  2. "{" not at the end of a line is appended to the previous line + *
  3. The content of a section is also placed between "{" and "}". + *
  4. Lines are trimmed
+ * @throws IOException if there is an I/O error + * @throws KrbException if there is a file format error */ - private Vector loadConfigFile(final String fileName) throws IOException { + private List loadConfigFile(final String fileName) + throws IOException, KrbException { try { - if (!fileName.equals("")) { - BufferedReader br = new BufferedReader(new InputStreamReader( - java.security.AccessController.doPrivileged( - new java.security.PrivilegedExceptionAction () { - public FileInputStream run() throws IOException { - return new FileInputStream(fileName); - } - }))); - String Line; - Vector v = new Vector<>(); + List v = new ArrayList<>(); + try (BufferedReader br = new BufferedReader(new InputStreamReader( + AccessController.doPrivileged( + new PrivilegedExceptionAction () { + public FileInputStream run() throws IOException { + return new FileInputStream(fileName); + } + })))) { + String line; String previous = null; - while ((Line = br.readLine()) != null) { - // ignore comments and blank line in the configuration file. - // Comments start with #. - if (!(Line.startsWith("#") || Line.trim().isEmpty())) { - String current = Line.trim(); - // In practice, a subsection might look like: - // EXAMPLE.COM = - // { - // kdc = kerberos.example.com - // ... - // } - // Before parsed into stanza table, it needs to be - // converted into formal style: - // EXAMPLE.COM = { - // kdc = kerberos.example.com - // ... - // } - // - // So, if a line is "{", adhere to the previous line. - if (current.equals("{")) { - if (previous == null) { - throw new IOException( - "Config file should not start with \"{\""); - } - previous += " " + current; - } else { - if (previous != null) { - v.addElement(previous); - } - previous = current; + while ((line = br.readLine()) != null) { + line = line.trim(); + if (line.startsWith("#") || line.isEmpty()) { + // ignore comments and blank line + // Comments start with #. + continue; + } + // In practice, a subsection might look like: + // [realms] + // EXAMPLE.COM = + // { + // kdc = kerberos.example.com + // ... + // } + // Before parsed into stanza table, it needs to be + // converted into a canonicalized style (no indent): + // realms = { + // EXAMPLE.COM = { + // kdc = kerberos.example.com + // ... + // } + // } + // + if (line.startsWith("[")) { + if (!line.endsWith("]")) { + throw new KrbException("Illegal config content:" + + line); + } + if (previous != null) { + v.add(previous); + v.add("}"); + } + String title = line.substring( + 1, line.length()-1).trim(); + if (title.isEmpty()) { + throw new KrbException("Illegal config content:" + + line); + } + previous = title + " = {"; + } else if (line.startsWith("{")) { + if (previous == null) { + throw new KrbException( + "Config file should not start with \"{\""); + } + previous += " {"; + if (line.length() > 1) { + // { and content on the same line + v.add(previous); + previous = line.substring(1).trim(); } + } else { + if (previous == null) { + throw new KrbException( + "Config file must starts with a section"); + } + v.add(previous); + previous = line; } } if (previous != null) { - v.addElement(previous); + v.add(previous); + v.add("}"); } - - br.close(); - return v; } - return null; + return v; } catch (java.security.PrivilegedActionException pe) { throw (IOException)pe.getException(); } } - /** * Parses stanza names and values from configuration file to * stanzaTable (Hashtable). Hashtable key would be stanza names, * (libdefaults, realms, domain_realms, etc), and the hashtable value * would be another hashtable which contains the key-value pairs under - * a stanza name. + * a stanza name. The value of this sub-hashtable can be another hashtable + * containing another sub-sub-section or a vector of strings for + * final values (even if there is only one value defined). + *

+ * For duplicates section names, the latter overwrites the former. For + * duplicate value names, the values are in a vector in its appearing order. + * + * Please note that this behavior is Java traditional. and it is + * not the same as the MIT krb5 behavior, where:

    + *
  1. Duplicated root sections will be merged + *
  2. For duplicated sub-sections, the former overwrites the latter + *
  3. Duplicate keys for values are always saved in a vector + *
+ * @param v the strings in the file, never null, might be empty + * @throws KrbException if there is a file format error */ - private Hashtable parseStanzaTable(Vector v) throws KrbException { - if (v == null) { - throw new KrbException("I/O error while reading" + - " configuration file."); - } - Hashtable table = new Hashtable<>(); - for (int i = 0; i < v.size(); i++) { - String line = v.elementAt(i).trim(); - if (line.equalsIgnoreCase("[realms]")) { - for (int count = i + 1; count < v.size() + 1; count++) { - // find the next stanza name - if ((count == v.size()) || - (v.elementAt(count).startsWith("["))) { - Hashtable>> temp = - new Hashtable<>(); - temp = parseRealmField(v, i + 1, count); - table.put("realms", temp); - i = count - 1; - break; - } + @SuppressWarnings("unchecked") + private Hashtable parseStanzaTable(List v) + throws KrbException { + Hashtable current = stanzaTable; + for (String line: v) { + // There are 3 kinds of lines + // 1. a = b + // 2. a = { + // 3. } + if (line.equals("}")) { + // Go back to parent, see below + current = (Hashtable)current.remove(" PARENT "); + if (current == null) { + throw new KrbException("Unmatched close brace"); } - } else if (line.equalsIgnoreCase("[capaths]")) { - for (int count = i + 1; count < v.size() + 1; count++) { - // find the next stanza name - if ((count == v.size()) || - (v.elementAt(count).startsWith("["))) { - Hashtable>> temp = - new Hashtable<>(); - temp = parseRealmField(v, i + 1, count); - table.put("capaths", temp); - i = count - 1; - break; - } + } else { + int pos = line.indexOf('='); + if (pos < 0) { + throw new KrbException("Illegal config content:" + line); } - } else if (line.startsWith("[") && line.endsWith("]")) { - String key = line.substring(1, line.length() - 1); - for (int count = i + 1; count < v.size() + 1; count++) { - // find the next stanza name - if ((count == v.size()) || - (v.elementAt(count).startsWith("["))) { - Hashtable temp = - parseField(v, i + 1, count); - table.put(key, temp); - i = count - 1; - break; + String key = line.substring(0, pos).trim(); + String value = trimmed(line.substring(pos+1)); + if (value.equals("{")) { + Hashtable subTable; + if (current == stanzaTable) { + key = key.toLowerCase(Locale.US); } + subTable = new Hashtable<>(); + current.put(key, subTable); + // A special entry for its parent. Put whitespaces around, + // so will never be confused with a normal key + subTable.put(" PARENT ", current); + current = subTable; + } else { + Vector values; + if (current.containsKey(key)) { + Object obj = current.get(key); + // If a key first shows as a section and then a value, + // this is illegal. However, we haven't really forbid + // first value then section, which the final result + // is a section. + if (!(obj instanceof Vector)) { + throw new KrbException("Key " + key + + "used for both value and section"); + } + values = (Vector)current.get(key); + } else { + values = new Vector(); + current.put(key, values); + } + values.add(value); } } } - return table; + if (current != stanzaTable) { + throw new KrbException("Not closed"); + } + return current; } /** @@ -807,158 +744,20 @@ public class Config { private static String trimmed(String s) { s = s.trim(); + if (s.isEmpty()) return s; if (s.charAt(0) == '"' && s.charAt(s.length()-1) == '"' || s.charAt(0) == '\'' && s.charAt(s.length()-1) == '\'') { s = s.substring(1, s.length()-1).trim(); } return s; } - /** - * Parses key-value pairs under a stanza name. - */ - private Hashtable parseField(Vector v, int start, int end) { - Hashtable table = new Hashtable<>(); - String line; - for (int i = start; i < end; i++) { - line = v.elementAt(i); - for (int j = 0; j < line.length(); j++) { - if (line.charAt(j) == '=') { - String key = (line.substring(0, j)).trim(); - String value = trimmed(line.substring(j + 1)); - table.put(key, value); - break; - } - } - } - return table; - } - - /** - * Parses key-value pairs under [realms]. The key would be the realm - * name, the value would be another hashtable which contains - * information for the realm given within a pair of braces. - */ - private Hashtable>> parseRealmField(Vector v, int start, int end) { - Hashtable>> table = new Hashtable<>(); - String line; - for (int i = start; i < end; i++) { - line = v.elementAt(i).trim(); - if (line.endsWith("{")) { - String key = ""; - for (int j = 0; j < line.length(); j++) { - if (line.charAt(j) == '=') { - key = line.substring(0, j).trim(); - // get the key - break; - } - } - for (int k = i + 1; k < end; k++) { - boolean found = false; - line = v.elementAt(k).trim(); - for (int l = 0; l < line.length(); l++) { - if (line.charAt(l) == '}') { - found = true; - break; - } - } - if (found == true) { - Hashtable> temp = parseRealmFieldEx(v, i + 1, k); - table.put(key, temp); - i = k; - found = false; - break; - } - - } - } - } - return table; - } - - /** - * Parses key-value pairs within each braces under [realms]. - */ - private Hashtable> parseRealmFieldEx(Vector v, int start, int end) { - Hashtable> table = new Hashtable<>(); - Vector keyVector = new Vector<>(); - Vector nameVector = new Vector<>(); - String line = ""; - String key; - for (int i = start; i < end; i++) { - line = v.elementAt(i); - for (int j = 0; j < line.length(); j++) { - if (line.charAt(j) == '=') { - int index; - key = line.substring(0, j).trim(); - if (! exists(key, keyVector)) { - keyVector.addElement(key); - nameVector = new Vector (); - } else { - nameVector = table.get(key); - } - nameVector.addElement(trimmed(line.substring(j + 1))); - table.put(key, nameVector); - break; - } - } - } - return table; - } - - /** - * Compares the key with the known keys to see if it exists. - */ - private boolean exists(String key, Vector v) { - boolean exists = false; - for (int i = 0; i < v.size(); i++) { - if (v.elementAt(i).equals(key)) { - exists = true; - } - } - return exists; - } /** * For testing purpose. This method lists all information being parsed from * the configuration file to the hashtable. */ public void listTable() { - listTable(stanzaTable); - } - - // stanzaTable leads to a lot of unchecked casts since its value type is - // STANZATABLE = String | Hashtable - @SuppressWarnings("unchecked") - private void listTable(Hashtable table) { - Vector v = new Vector(); - String key; - if (stanzaTable != null) { - for (Enumeration e = table.keys(); e.hasMoreElements(); ) { - key = e.nextElement(); - Object object = table.get(key); - if (table == stanzaTable) { - System.out.println("[" + key + "]"); - } - if (object instanceof Hashtable) { - if (table != stanzaTable) - System.out.println("\t" + key + " = {"); - listTable((Hashtable)object); - if (table != stanzaTable) - System.out.println("\t}"); - - } else if (object instanceof String) { - System.out.println("\t" + key + " = " + - (String)table.get(key)); - } else if (object instanceof Vector) { - v = (Vector)object; - for (int i = 0; i < v.size(); i++) { - System.out.println("\t" + key + " = " + v.elementAt(i)); - } - } - } - } else { - System.out.println("Configuration file not found."); - } + System.out.println(this); } /** @@ -967,7 +766,7 @@ public class Config { */ public int[] defaultEtype(String enctypes) { String default_enctypes; - default_enctypes = getDefault(enctypes, "libdefaults"); + default_enctypes = get("libdefaults", enctypes); String delim = " "; StringTokenizer st; int[] etype; @@ -991,7 +790,7 @@ public class Config { ArrayList ls = new ArrayList<>(len); int type; for (int i = 0; i < len; i++) { - type = getType(st.nextToken()); + type = Config.getType(st.nextToken()); if ((type != -1) && (EType.isSupported(type))) { ls.add(type); @@ -1032,7 +831,7 @@ public class Config { * checksum type to int value that can be later used by EType and * Checksum classes. */ - public int getType(String input) { + public static int getType(String input) { int result = -1; if (input == null) { return result; @@ -1114,11 +913,11 @@ public class Config { public boolean useAddresses() { boolean useAddr = false; // use addresses if "no_addresses" is set to false - String value = getDefault("no_addresses", "libdefaults"); + String value = get("libdefaults", "no_addresses"); useAddr = (value != null && value.equalsIgnoreCase("false")); if (useAddr == false) { // use addresses if "noaddresses" is set to false - value = getDefault("noaddresses", "libdefaults"); + value = get("libdefaults", "noaddresses"); useAddr = (value != null && value.equalsIgnoreCase("false")); } return useAddr; @@ -1127,10 +926,10 @@ public class Config { /** * Check if need to use DNS to locate Kerberos services */ - public boolean useDNS(String name) { - String value = getDefault(name, "libdefaults"); + private boolean useDNS(String name) { + String value = get("libdefaults", name); if (value == null) { - value = getDefault("dns_fallback", "libdefaults"); + value = get("libdefaults", "dns_fallback"); if ("false".equalsIgnoreCase(value)) { return false; } else { @@ -1144,14 +943,14 @@ public class Config { /** * Check if need to use DNS to locate the KDC */ - public boolean useDNS_KDC() { + private boolean useDNS_KDC() { return useDNS("dns_lookup_kdc"); } /* * Check if need to use DNS to locate the Realm */ - public boolean useDNS_Realm() { + private boolean useDNS_Realm() { return useDNS("dns_lookup_realm"); } @@ -1165,7 +964,7 @@ public class Config { return defaultRealm; } Exception cause = null; - String realm = getDefault("default_realm", "libdefaults"); + String realm = get("libdefaults", "default_realm"); if ((realm == null) && useDNS_Realm()) { // use DNS to locate Kerberos realm try { @@ -1212,7 +1011,7 @@ public class Config { return defaultKDC; } Exception cause = null; - String kdcs = getDefault("kdc", realm); + String kdcs = getAll("realms", realm, "kdc"); if ((kdcs == null) && useDNS_KDC()) { // use DNS to locate KDC try { diff --git a/src/share/classes/sun/security/krb5/KdcComm.java b/src/share/classes/sun/security/krb5/KdcComm.java index 756beb989..5401dfec0 100644 --- a/src/share/classes/sun/security/krb5/KdcComm.java +++ b/src/share/classes/sun/security/krb5/KdcComm.java @@ -142,11 +142,11 @@ public final class KdcComm { try { Config cfg = Config.getInstance(); - String temp = cfg.getDefault("kdc_timeout", "libdefaults"); + String temp = cfg.get("libdefaults", "kdc_timeout"); timeout = parsePositiveIntString(temp); - temp = cfg.getDefault("max_retries", "libdefaults"); + temp = cfg.get("libdefaults", "max_retries"); max_retries = parsePositiveIntString(temp); - temp = cfg.getDefault("udp_preference_limit", "libdefaults"); + temp = cfg.get("libdefaults", "udp_preference_limit"); udf_pref_limit = parsePositiveIntString(temp); } catch (Exception exc) { // ignore any exceptions; use default values @@ -421,7 +421,7 @@ public final class KdcComm { int temp = -1; try { String value = - Config.getInstance().getDefault(key, realm); + Config.getInstance().get("realms", realm, key); temp = parsePositiveIntString(value); } catch (Exception exc) { // Ignored, defValue will be picked up diff --git a/src/share/classes/sun/security/krb5/PrincipalName.java b/src/share/classes/sun/security/krb5/PrincipalName.java index 2a1e47537..0386d61ba 100644 --- a/src/share/classes/sun/security/krb5/PrincipalName.java +++ b/src/share/classes/sun/security/krb5/PrincipalName.java @@ -655,19 +655,19 @@ public class PrincipalName implements Cloneable { try { String subname = null; Config c = Config.getInstance(); - if ((result = c.getDefault(name, "domain_realm")) != null) + if ((result = c.get("domain_realm", name)) != null) return result; else { for (int i = 1; i < name.length(); i++) { if ((name.charAt(i) == '.') && (i != name.length() - 1)) { //mapping could be .ibm.com = AUSTIN.IBM.COM subname = name.substring(i); - result = c.getDefault(subname, "domain_realm"); + result = c.get("domain_realm", subname); if (result != null) { break; } else { subname = name.substring(i + 1); //or mapping could be ibm.com = AUSTIN.IBM.COM - result = c.getDefault(subname, "domain_realm"); + result = c.get("domain_realm", subname); if (result != null) { break; } diff --git a/src/share/classes/sun/security/krb5/Realm.java b/src/share/classes/sun/security/krb5/Realm.java index bfb43e757..151da7101 100644 --- a/src/share/classes/sun/security/krb5/Realm.java +++ b/src/share/classes/sun/security/krb5/Realm.java @@ -350,7 +350,7 @@ public class Realm implements Cloneable { return null; } - String intermediaries = cfg.getDefault(sRealm, cRealm); + String intermediaries = cfg.getAll("capaths", cRealm, sRealm); if (intermediaries == null) { if (DEBUG) { @@ -459,7 +459,7 @@ public class Realm implements Cloneable { tempTarget); } - intermediaries = cfg.getDefault(tempTarget, cRealm); + intermediaries = cfg.getAll("capaths", cRealm, tempTarget); } while (true); diff --git a/src/share/classes/sun/security/krb5/SCDynamicStoreConfig.java b/src/share/classes/sun/security/krb5/SCDynamicStoreConfig.java index c6e5e70a9..391be5eac 100644 --- a/src/share/classes/sun/security/krb5/SCDynamicStoreConfig.java +++ b/src/share/classes/sun/security/krb5/SCDynamicStoreConfig.java @@ -34,19 +34,25 @@ import java.util.Vector; public class SCDynamicStoreConfig { private static native void installNotificationCallback(); private static native Hashtable getKerberosConfig(); + private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; static { - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Void run() { - System.loadLibrary("osx"); - return null; + boolean isMac = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Boolean run() { + String osname = System.getProperty("os.name"); + if (osname.contains("OS X")) { + System.loadLibrary("osx"); + return true; + } + return false; } }); - installNotificationCallback(); + if (isMac) installNotificationCallback(); } - private static Vector unwrapHost(Collection> c) { + private static Vector unwrapHost( + Collection> c) { Vector vector = new Vector(); for (Hashtable m : c) { vector.add(m.get("host")); @@ -60,20 +66,25 @@ public class SCDynamicStoreConfig { * are wrapped inside Hashtables */ @SuppressWarnings("unchecked") - private static Hashtable convertRealmConfigs(Hashtable configs) { + private static Hashtable + convertRealmConfigs(Hashtable configs) { Hashtable realmsTable = new Hashtable(); for (String realm : configs.keySet()) { // get the kdc - Hashtable> map = (Hashtable>) configs.get(realm); - Collection> kdc = (Collection>) map.get("kdc"); + Hashtable> map = + (Hashtable>) configs.get(realm); + Hashtable> realmMap = + new Hashtable>(); // put the kdc into the realmMap - Hashtable> realmMap = new Hashtable>(); + Collection> kdc = + (Collection>) map.get("kdc"); if (kdc != null) realmMap.put("kdc", unwrapHost(kdc)); // put the admin server into the realmMap - Collection> kadmin = (Collection>) map.get("kadmin"); + Collection> kadmin = + (Collection>) map.get("kadmin"); if (kadmin != null) realmMap.put("admin_server", unwrapHost(kadmin)); // add the full entry to the realmTable @@ -90,23 +101,44 @@ public class SCDynamicStoreConfig { * @return * @throws IOException */ - @SuppressWarnings("unchecked") public static Hashtable getConfig() throws IOException { Hashtable stanzaTable = getKerberosConfig(); if (stanzaTable == null) { - throw new IOException("Could not load configuration from SCDynamicStore"); + throw new IOException( + "Could not load configuration from SCDynamicStore"); } - //System.out.println("Raw map from JNI: " + stanzaTable); + if (DEBUG) System.out.println("Raw map from JNI: " + stanzaTable); + return convertNativeConfig(stanzaTable); + } + @SuppressWarnings("unchecked") + private static Hashtable convertNativeConfig( + Hashtable stanzaTable) { // convert SCDynamicStore realm structure to Java realm structure - Hashtable realms = (Hashtable) stanzaTable.get("realms"); + Hashtable realms = + (Hashtable) stanzaTable.get("realms"); if (realms != null) { stanzaTable.remove("realms"); Hashtable realmsTable = convertRealmConfigs(realms); stanzaTable.put("realms", realmsTable); } - - // System.out.println("stanzaTable : " + stanzaTable); + WrapAllStringInVector(stanzaTable); + if (DEBUG) System.out.println("stanzaTable : " + stanzaTable); return stanzaTable; } + + @SuppressWarnings("unchecked") + private static void WrapAllStringInVector( + Hashtable stanzaTable) { + for (String s: stanzaTable.keySet()) { + Object v = stanzaTable.get(s); + if (v instanceof Hashtable) { + WrapAllStringInVector((Hashtable)v); + } else if (v instanceof String) { + Vector vec = new Vector<>(); + vec.add((String)v); + stanzaTable.put(s, vec); + } + } + } } diff --git a/src/share/classes/sun/security/krb5/internal/KDCOptions.java b/src/share/classes/sun/security/krb5/internal/KDCOptions.java index df1c549b7..b0d609d9a 100644 --- a/src/share/classes/sun/security/krb5/internal/KDCOptions.java +++ b/src/share/classes/sun/security/krb5/internal/KDCOptions.java @@ -244,25 +244,23 @@ public class KDCOptions extends KerberosFlags { Config config = Config.getInstance(); - /* - * First see if the IBM hex format is being used. - * If not, try the Sun's string (boolean) format. - */ + // If key not present, returns Integer.MIN_VALUE, which is + // almost all zero. - int options =config.getDefaultIntValue("kdc_default_options", - "libdefaults"); + int options = config.getIntValue("libdefaults", + "kdc_default_options"); if ((options & RENEWABLE_OK) == RENEWABLE_OK) { set(RENEWABLE_OK, true); } else { - if (config.getDefaultBooleanValue("renewable", "libdefaults")) { + if (config.getBooleanValue("libdefaults", "renewable")) { set(RENEWABLE_OK, true); } } if ((options & PROXIABLE) == PROXIABLE) { set(PROXIABLE, true); } else { - if (config.getDefaultBooleanValue("proxiable", "libdefaults")) { + if (config.getBooleanValue("libdefaults", "proxiable")) { set(PROXIABLE, true); } } @@ -270,7 +268,7 @@ public class KDCOptions extends KerberosFlags { if ((options & FORWARDABLE) == FORWARDABLE) { set(FORWARDABLE, true); } else { - if (config.getDefaultBooleanValue("forwardable", "libdefaults")) { + if (config.getBooleanValue("libdefaults", "forwardable")) { set(FORWARDABLE, true); } } diff --git a/src/share/classes/sun/security/krb5/internal/KerberosTime.java b/src/share/classes/sun/security/krb5/internal/KerberosTime.java index 1ad85ec50..ce141419f 100644 --- a/src/share/classes/sun/security/krb5/internal/KerberosTime.java +++ b/src/share/classes/sun/security/krb5/internal/KerberosTime.java @@ -350,9 +350,9 @@ public class KerberosTime implements Cloneable { public static int getDefaultSkew() { int tdiff = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW; try { - Config c = Config.getInstance(); - if ((tdiff = c.getDefaultIntValue("clockskew", - "libdefaults")) == Integer.MIN_VALUE) { //value is not defined + if ((tdiff = Config.getInstance().getIntValue( + "libdefaults", "clockskew")) + == Integer.MIN_VALUE) { //value is not defined tdiff = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW; } } catch (KrbException e) { diff --git a/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java index 1896b4025..eb4a1b1cb 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java @@ -126,10 +126,10 @@ public abstract class CksumType { int cksumType = Checksum.CKSUMTYPE_RSA_MD5; // default try { Config c = Config.getInstance(); - if ((cksumType = (c.getType(c.getDefault("ap_req_checksum_type", - "libdefaults")))) == - 1) { - if ((cksumType = c.getType(c.getDefault("checksum_type", - "libdefaults"))) == -1) { + if ((cksumType = (Config.getType(c.get("libdefaults", + "ap_req_checksum_type")))) == - 1) { + if ((cksumType = Config.getType(c.get("libdefaults", + "checksum_type"))) == -1) { cksumType = Checksum.CKSUMTYPE_RSA_MD5; // default } } diff --git a/src/share/classes/sun/security/krb5/internal/crypto/EType.java b/src/share/classes/sun/security/krb5/internal/crypto/EType.java index 90082b12a..e46c049bc 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/EType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/EType.java @@ -48,13 +48,17 @@ import java.util.ArrayList; public abstract class EType { private static final boolean DEBUG = Krb5.DEBUG; - private static final boolean ALLOW_WEAK_CRYPTO; + private static boolean allowWeakCrypto; static { + initStatic(); + } + + public static void initStatic() { boolean allowed = true; try { Config cfg = Config.getInstance(); - String temp = cfg.getDefault("allow_weak_crypto", "libdefaults"); + String temp = cfg.get("libdefaults", "allow_weak_crypto"); if (temp != null && temp.equals("false")) allowed = false; } catch (Exception exc) { if (DEBUG) { @@ -63,7 +67,7 @@ public abstract class EType { exc.getMessage()); } } - ALLOW_WEAK_CRYPTO = allowed; + allowWeakCrypto = allowed; } public static EType getInstance (int eTypeConst) @@ -216,7 +220,7 @@ public abstract class EType { } else { result = BUILTIN_ETYPES; } - if (!ALLOW_WEAK_CRYPTO) { + if (!allowWeakCrypto) { // The last 2 etypes are now weak ones return Arrays.copyOfRange(result, 0, result.length - 2); } diff --git a/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java b/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java index 4b0ee703a..f5029e676 100644 --- a/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java +++ b/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java @@ -186,8 +186,8 @@ public class KeyTab implements KeyTabConstants { } else { String kname = null; try { - String keytab_names = Config.getInstance().getDefault - ("default_keytab_name", "libdefaults"); + String keytab_names = Config.getInstance().get + ("libdefaults", "default_keytab_name"); if (keytab_names != null) { StringTokenizer st = new StringTokenizer(keytab_names, " "); while (st.hasMoreTokens()) { diff --git a/test/sun/security/krb5/ConfPlusProp.java b/test/sun/security/krb5/ConfPlusProp.java index 9fe1adcf4..caf7d6288 100644 --- a/test/sun/security/krb5/ConfPlusProp.java +++ b/test/sun/security/krb5/ConfPlusProp.java @@ -25,6 +25,7 @@ * @bug 6857795 * @bug 6858589 * @bug 6972005 + * @compile -XDignore.symbol.file ConfPlusProp.java * @run main/othervm ConfPlusProp * @summary krb5.conf ignored if system properties on realm and kdc are provided */ @@ -75,7 +76,7 @@ public class ConfPlusProp { check("R1", "k1"); check("R2", "old"); check("R3", null); - if (!config.getDefault("forwardable", "libdefaults").equals("well")) { + if (!config.get("libdefaults", "forwardable").equals("well")) { throw new Exception("Extra config error"); } @@ -103,7 +104,7 @@ public class ConfPlusProp { check("R1", null); check("R2", null); check("R3", null); - if (config.getDefault("forwardable", "libdefaults") != null) { + if (config.get("libdefaults", "forwardable") != null) { throw new Exception("Extra config error"); } } @@ -121,7 +122,7 @@ public class ConfPlusProp { check("R1", "k1"); check("R2", "k2"); check("R3", "k2"); - if (!config.getDefault("forwardable", "libdefaults").equals("well")) { + if (!config.get("libdefaults", "forwardable").equals("well")) { throw new Exception("Extra config error"); } @@ -143,7 +144,7 @@ public class ConfPlusProp { check("R1", "k2"); check("R2", "k2"); check("R3", "k2"); - if (config.getDefault("forwardable", "libdefaults") != null) { + if (config.get("libdefaults", "forwardable") != null) { throw new Exception("Extra config error"); } } diff --git a/test/sun/security/krb5/DnsFallback.java b/test/sun/security/krb5/DnsFallback.java index 3a48b05d8..2702d365c 100644 --- a/test/sun/security/krb5/DnsFallback.java +++ b/test/sun/security/krb5/DnsFallback.java @@ -28,12 +28,20 @@ * @summary fix dns_fallback parse error, and use dns by default */ -import sun.security.krb5.*; import java.io.*; +import java.lang.reflect.Method; +import sun.security.krb5.Config; public class DnsFallback { + + static Method useDNS_Realm; + public static void main(String[] args) throws Exception { + useDNS_Realm = Config.class.getDeclaredMethod("useDNS_Realm"); + useDNS_Realm.setAccessible(true); + + // for 6673164 check("true", "true", true); check("false", "true", false); @@ -48,22 +56,25 @@ public class DnsFallback { check(null, null, true); } - static void check(String realm, String fallback, boolean output) throws Exception { - FileOutputStream fo = new FileOutputStream("dnsfallback.conf"); - StringBuffer sb = new StringBuffer(); - sb.append("[libdefaults]\n"); - if (realm != null) { - sb.append("dns_lookup_realm=" + realm + "\n"); - } - if (fallback != null) { - sb.append("dns_fallback=" + fallback + "\n"); + static void check(String realm, String fallback, boolean output) + throws Exception { + + try (PrintStream ps = + new PrintStream(new FileOutputStream("dnsfallback.conf"))) { + ps.println("[libdefaults]\n"); + if (realm != null) { + ps.println("dns_lookup_realm=" + realm); + } + if (fallback != null) { + ps.println("dns_fallback=" + fallback); + } } - fo.write(sb.toString().getBytes()); - fo.close(); + System.setProperty("java.security.krb5.conf", "dnsfallback.conf"); Config.refresh(); System.out.println("Testing " + realm + ", " + fallback + ", " + output); - if (Config.getInstance().useDNS_Realm() != output) { + + if (!useDNS_Realm.invoke(Config.getInstance()).equals(output)) { throw new Exception("Fail"); } } diff --git a/test/sun/security/krb5/ParseConfig.java b/test/sun/security/krb5/ParseConfig.java index 43c5ce39f..b4e206021 100644 --- a/test/sun/security/krb5/ParseConfig.java +++ b/test/sun/security/krb5/ParseConfig.java @@ -23,6 +23,7 @@ /* * @test * @bug 6319046 + * @compile -XDignore.symbol.file ParseConfig.java * @run main/othervm ParseConfig * @summary Problem with parsing krb5.conf */ @@ -37,7 +38,7 @@ public class ParseConfig { String sample = "kdc.example.com kdc2.example.com"; for ( int i = 0; i < 4; i++ ) { - String expected = config.getDefault("kdc", "EXAMPLE_" + i + ".COM"); + String expected = config.getAll("realms", "EXAMPLE_" + i + ".COM", "kdc"); if (!sample.equals(expected)) { throw new Exception("krb5.conf: unexpected kdc value \"" + expected + "\""); diff --git a/test/sun/security/krb5/auto/BasicKrb5Test.java b/test/sun/security/krb5/auto/BasicKrb5Test.java index aaf6b1266..bd01d253b 100644 --- a/test/sun/security/krb5/auto/BasicKrb5Test.java +++ b/test/sun/security/krb5/auto/BasicKrb5Test.java @@ -25,6 +25,7 @@ * @test * @bug 6706974 * @summary Add krb5 test infrastructure + * @compile -XDignore.symbol.file BasicKrb5Test.java * @run main/othervm BasicKrb5Test * @run main/othervm BasicKrb5Test des-cbc-crc * @run main/othervm BasicKrb5Test des-cbc-md5 @@ -86,7 +87,7 @@ public class BasicKrb5Test { new OneKDC(etype).writeJAASConf(); System.out.println("Testing etype " + etype); - if (etype != null && !EType.isSupported(Config.getInstance().getType(etype))) { + if (etype != null && !EType.isSupported(Config.getType(etype))) { // aes256 is not enabled on all systems System.out.println("Not supported."); return; diff --git a/test/sun/security/krb5/auto/MaxRetries.java b/test/sun/security/krb5/auto/MaxRetries.java index f4f86a3fc..bf5d461f8 100644 --- a/test/sun/security/krb5/auto/MaxRetries.java +++ b/test/sun/security/krb5/auto/MaxRetries.java @@ -108,7 +108,7 @@ public class MaxRetries { if (line.startsWith(">>> KDCCommunication")) { System.out.println(line); if (line.indexOf(timeoutTag) < 0) { - throw new Exception("Wrong timeout value"); + throw new Exception("Wrong timeout value" + timeoutTag); } count--; } diff --git a/test/sun/security/krb5/config/Duplicates.java b/test/sun/security/krb5/config/Duplicates.java new file mode 100644 index 000000000..0d8bac70c --- /dev/null +++ b/test/sun/security/krb5/config/Duplicates.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 7184246 + * @compile -XDignore.symbol.file Duplicates.java + * @run main/othervm Duplicates + * @summary Simplify Config.get() of krb5 + */ + +import sun.security.krb5.Config; + +public class Duplicates { + public static void main(String[] args) throws Exception { + System.setProperty("java.security.krb5.conf", + System.getProperty("test.src", ".") +"/k1.conf"); + Config config = Config.getInstance(); + config.listTable(); + String s; + + // Latter overwrites former for root section + s = config.get("libdefaults", "default_realm"); + if (s != null) { + throw new Exception(); + } + // Latter overwrites former for strings + s = config.get("libdefaults", "default_tkt_enctypes"); + if (!s.equals("aes256-cts")) { + throw new Exception(); + } + // Latter overwrites former for sub-section + s = config.get("realms", "R1", "kdc"); + if (!s.equals("k2")) { + throw new Exception(s); + } + // Duplicate keys in [realms] are merged + s = config.getAll("realms", "R2", "kdc"); + if (!s.equals("k1 k2 k3 k4")) { + throw new Exception(s); + } + // Duplicate keys in [capaths] are merged + s = config.getAll("capaths", "R1", "R2"); + if (!s.equals("R3 R4 R5 R6")) { + throw new Exception(s); + } + // We can be very deep now + s = config.get("new", "x", "y", "z", "a", "b", "c"); + if (!s.equals("d")) { + throw new Exception(s); + } + } +} diff --git a/test/sun/security/krb5/config/SCDynamicConfigTest.java b/test/sun/security/krb5/config/SCDynamicConfigTest.java new file mode 100644 index 000000000..b74992731 --- /dev/null +++ b/test/sun/security/krb5/config/SCDynamicConfigTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7184246 + * @summary Simplify Config.get() of krb5 + */ +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Hashtable; +import java.util.Vector; +import sun.security.krb5.Config; +import sun.security.krb5.SCDynamicStoreConfig; + +public class SCDynamicConfigTest { + + static Vector>hosts() { + Vector > result = new Vector<>(); + Hashtable pair = new Hashtable<>(); + pair.put("host", "127.0.0.1"); + result.add(pair); + pair = new Hashtable<>(); + pair.put("host", "127.0.0.2"); + result.add(pair); + return result; + } + + public static void main(String[] args) throws Exception { + // Reconstruct a typical SCDynamicConfig.getKerberosConfig() output + Hashtable conf = new Hashtable<>(); + + Hashtable libdefaults = new Hashtable<>(); + libdefaults.put("default_realm", "REALM.COM"); + conf.put("libdefaults", libdefaults); + + Hashtable realms = new Hashtable<>(); + Hashtable thisRealm = new Hashtable<>(); + realms.put("REALM.COM", thisRealm); + thisRealm.put("kpasswd", hosts()); + thisRealm.put("kadmin", hosts()); + thisRealm.put("kdc", hosts()); + conf.put("realms", realms); + + Hashtable domain_realm = new Hashtable<>(); + domain_realm.put(".realm.com", "REALM.COM"); + domain_realm.put("realm.com", "REALM.COM"); + conf.put("domain_realm", domain_realm); + + System.out.println("SCDynamicConfig:\n"); + System.out.println(conf); + + // Simulate SCDynamicConfig.getConfig() output + Method m = SCDynamicStoreConfig.class.getDeclaredMethod( + "convertNativeConfig", Hashtable.class); + m.setAccessible(true); + conf = (Hashtable)m.invoke(null, conf); + + System.out.println("\nkrb5.conf:\n"); + System.out.println(conf); + + // Feed it into a Config object + System.setProperty("java.security.krb5.conf", "not-a-file"); + Config cf = Config.getInstance(); + Field f = Config.class.getDeclaredField("stanzaTable"); + f.setAccessible(true); + f.set(cf, conf); + + System.out.println("\nConfig:\n"); + System.out.println(cf); + + if (!cf.getDefaultRealm().equals("REALM.COM")) { + throw new Exception(); + } + if (!cf.getKDCList("REALM.COM").equals("127.0.0.1 127.0.0.2")) { + throw new Exception(); + } + if (!cf.get("domain_realm", ".realm.com").equals("REALM.COM")) { + throw new Exception(); + } + } +} diff --git a/test/sun/security/krb5/config/k1.conf b/test/sun/security/krb5/config/k1.conf new file mode 100644 index 000000000..76b8513e7 --- /dev/null +++ b/test/sun/security/krb5/config/k1.conf @@ -0,0 +1,40 @@ +[libdefaults] +default_realm = R1 + +[libdefaults] +default_tkt_enctypes = aes128-cts +default_tkt_enctypes = aes256-cts + +[realms] +R1 = { + kdc = k1 +} +R1 = { + kdc = k2 +} +R2 = { + kdc = k1 + kdc = k2 k3 + admin_server = a1 + kdc = k4 +} + +[capaths] +R1 = { + R2 = R3 + R2 = R4 R5 + R2 = R6 +} + +[new] +x = { + y = { + z = { + a = { + b = { + c = d + } + } + } + } +} -- GitLab