Mercurial > hg > openjdk > icedtea > jdk7 > jdk
changeset 2481:4c8075f8c0ee
6844193: support max_retries in krb5.conf
Reviewed-by: valeriep
author | weijun |
---|---|
date | Thu, 29 Apr 2010 15:51:10 +0800 |
parents | b833a422c776 |
children | 937ec1a4ea35 |
files | src/share/classes/sun/security/krb5/Config.java src/share/classes/sun/security/krb5/KrbKdcReq.java test/sun/security/krb5/auto/MaxRetries.java |
diffstat | 3 files changed, 293 insertions(+), 55 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/sun/security/krb5/Config.java Thu Apr 29 15:50:40 2010 +0800 +++ b/src/share/classes/sun/security/krb5/Config.java Thu Apr 29 15:51:10 2010 +0800 @@ -1,5 +1,5 @@ /* - * Portions Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2000-2010 Sun Microsystems, Inc. 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 @@ -109,7 +109,7 @@ public static synchronized void refresh() throws KrbException { singleton = new Config(); KeyTab.refresh(); - KrbKdcReq.KdcAccessibility.reset(); + KrbKdcReq.initStatic(); }
--- a/src/share/classes/sun/security/krb5/KrbKdcReq.java Thu Apr 29 15:50:40 2010 +0800 +++ b/src/share/classes/sun/security/krb5/KrbKdcReq.java Thu Apr 29 15:51:10 2010 +0800 @@ -1,5 +1,5 @@ /* - * Portions Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2000-2010 Sun Microsystems, Inc. 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 @@ -51,28 +51,31 @@ public abstract class KrbKdcReq { - // Currently there is no option to specify retries - // in the kerberos configuration file - - private static final int DEFAULT_KDC_RETRY_LIMIT = Krb5.KDC_RETRY_LIMIT; + // The following settings can be configured in [libdefaults] + // section of krb5.conf, which are global for all realms. Each of + // them can also be defined in a realm, which overrides value here. /** - * Default timeout period when requesting a ticket from a KDC. - * If not specified in the configuration file, - * a value of 30 seconds is used. + * max retry time for a single KDC, default Krb5.KDC_RETRY_LIMIT (3) + */ + private static int defaultKdcRetryLimit; + /** + * timeout requesting a ticket from KDC, in millisec, default 30 sec */ - public static final int DEFAULT_KDC_TIMEOUT; // milliseconds + private static int defaultKdcTimeout; + /** + * max UDP packet size, default unlimited (-1) + */ + private static int defaultUdpPrefLimit; private static final boolean DEBUG = Krb5.DEBUG; - private static int udpPrefLimit = -1; - private static final String BAD_POLICY_KEY = "krb5.kdc.bad.policy"; /** * What to do when a KDC is unavailable, specified in the * java.security file with key krb5.kdc.bad.policy. - * Possible values can be TRY_LAST or TRY_LESS + * Possible values can be TRY_LAST or TRY_LESS. Reloaded when refreshed. */ private enum BpType { NONE, TRY_LAST, TRY_LESS @@ -80,9 +83,16 @@ private static int tryLessMaxRetries = 1; private static int tryLessTimeout = 5000; - private static final BpType badPolicy; + private static BpType badPolicy; static { + initStatic(); + } + + /** + * Read global settings + */ + public static void initStatic() { String value = AccessController.doPrivileged( new PrivilegedAction<String>() { public String run() { @@ -95,9 +105,21 @@ if ("tryless".equals(ss[0])) { if (ss.length > 1) { String[] params = ss[1].split(","); - tryLessMaxRetries = Integer.parseInt(params[0]); - if (params.length > 1) { - tryLessTimeout = Integer.parseInt(params[1]); + try { + int tmp0 = Integer.parseInt(params[0]); + if (params.length > 1) { + tryLessTimeout = Integer.parseInt(params[1]); + } + // Assign here in case of exception at params[1] + tryLessMaxRetries = tmp0; + } catch (NumberFormatException nfe) { + // Ignored. Please note that tryLess is recognized and + // used, parameters using default values + if (DEBUG) { + System.out.println("Invalid " + BAD_POLICY_KEY + + " parameter for tryLess: " + + value + ", use default"); + } } } badPolicy = BpType.TRY_LESS; @@ -110,30 +132,33 @@ badPolicy = BpType.NONE; } - /* - * Get default timeout. - */ int timeout = -1; + int max_retries = -1; + int udf_pref_limit = -1; + try { Config cfg = Config.getInstance(); String temp = cfg.getDefault("kdc_timeout", "libdefaults"); timeout = parsePositiveIntString(temp); + temp = cfg.getDefault("max_retries", "libdefaults"); + max_retries = parsePositiveIntString(temp); temp = cfg.getDefault("udp_preference_limit", "libdefaults"); - udpPrefLimit = parsePositiveIntString(temp); + udf_pref_limit = parsePositiveIntString(temp); } catch (Exception exc) { - // ignore any exceptions; use the default time out values + // ignore any exceptions; use default values if (DEBUG) { - System.out.println ("Exception in getting kdc_timeout value, " + - "using default value " + + System.out.println ("Exception in getting KDC communication " + + "settings, using default value " + exc.getMessage()); } } + defaultKdcTimeout = timeout > 0 ? timeout : 30*1000; // 30 seconds + defaultKdcRetryLimit = + max_retries > 0 ? max_retries : Krb5.KDC_RETRY_LIMIT; + defaultUdpPrefLimit = udf_pref_limit; - if (timeout > 0) - DEFAULT_KDC_TIMEOUT = timeout; - else - DEFAULT_KDC_TIMEOUT = 30*1000; // 30 seconds + KdcAccessibility.reset(); } protected byte[] obuf; @@ -151,6 +176,9 @@ public String send(String realm) throws IOException, KrbException { + int udpPrefLimit = getRealmSpecificValue( + realm, "udp_preference_limit", defaultUdpPrefLimit); + boolean useTCP = (udpPrefLimit > 0 && (obuf != null && obuf.length > udpPrefLimit)); @@ -213,9 +241,10 @@ return; int port = Krb5.KDC_INET_DEFAULT_PORT; - int retries = DEFAULT_KDC_RETRY_LIMIT; - int timeout = getKdcTimeout(realm); - + int retries = getRealmSpecificValue( + realm, "max_retries", defaultKdcRetryLimit); + int timeout = getRealmSpecificValue( + realm, "kdc_timeout", defaultKdcTimeout); if (badPolicy == BpType.TRY_LESS && KdcAccessibility.isBad(tempKdc)) { if (retries > tryLessMaxRetries) { @@ -322,6 +351,12 @@ if (useTCP) { TCPClient kdcClient = new TCPClient(kdc, port); + if (DEBUG) { + System.out.println(">>> KDCCommunication: kdc=" + kdc + + " TCP:" + + port + + ", #bytes=" + obuf.length); + } try { /* * Send the data to the kdc. @@ -336,7 +371,7 @@ } } else { - // For each KDC we try DEFAULT_KDC_RETRY_LIMIT (3) times to + // For each KDC we try defaultKdcRetryLimit times to // get the response for (int i=1; i <= retries; i++) { UDPClient kdcClient = new UDPClient(kdc, port, timeout); @@ -382,37 +417,37 @@ } /** - * Returns a timeout value for the KDC of the given realm. - * A KDC-specific timeout, if specified in the config file, - * overrides the default timeout (which may also be specified - * in the config file). Default timeout is returned if null - * is specified for realm. - * @param realm the realm which kdc's timeout is requested - * @return KDC timeout + * Returns krb5.conf setting of {@code key} for a specfic realm, + * which can be: + * 1. defined in the sub-stanza for the given realm inside [realms], or + * 2. defined in [libdefaults], or + * 3. defValue + * @param realm the given realm in which the setting is requested. Returns + * the global setting if null + * @param key the key for the setting + * @param defValue default value + * @return a value for the key */ - private int getKdcTimeout(String realm) - { - int timeout = DEFAULT_KDC_TIMEOUT; + private int getRealmSpecificValue(String realm, String key, int defValue) { + int v = defValue; - if (realm == null) - return timeout; + if (realm == null) return v; - int tempTimeout = -1; + int temp = -1; try { - String temp = - Config.getInstance().getDefault("kdc_timeout", realm); - tempTimeout = parsePositiveIntString(temp); + String value = + Config.getInstance().getDefault(key, realm); + temp = parsePositiveIntString(value); } catch (Exception exc) { + // Ignored, defValue will be picked up } - if (tempTimeout > 0) - timeout = tempTimeout; + if (temp > 0) v = temp; - return timeout; + return v; } - private static int parsePositiveIntString(String intString) - { + private static int parsePositiveIntString(String intString) { if (intString == null) return -1; @@ -461,7 +496,7 @@ return bads.contains(kdc); } - public static synchronized void reset() { + private static synchronized void reset() { if (DEBUG) { System.out.println(">>> KdcAccessibility: reset"); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/krb5/auto/MaxRetries.java Thu Apr 29 15:51:10 2010 +0800 @@ -0,0 +1,203 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6844193 + * @run main/timeout=300 MaxRetries + * @summary support max_retries in krb5.conf + */ + +import java.io.*; +import java.security.Security; + +public class MaxRetries { + public static void main(String[] args) + throws Exception { + + System.setProperty("sun.security.krb5.debug", "true"); + new OneKDC(null).writeJAASConf(); + System.setProperty("java.security.krb5.conf", "alternative-krb5.conf"); + + // For tryLast + Security.setProperty("krb5.kdc.bad.policy", "trylast"); + rewriteMaxRetries(4); + test1(4000, 6); // 1 1 1 1 2 2 + test1(4000, 2); // 2 2 + + rewriteMaxRetries(1); + test1(1000, 3); // 1 2 2 + test1(1000, 2); // 2 2 + + rewriteMaxRetries(-1); + test1(5000, 4); // 1 1 2 2 + test1(5000, 2); // 2 2 + + // For tryLess + Security.setProperty("krb5.kdc.bad.policy", "tryless"); + rewriteMaxRetries(4); + test1(4000, 7); // 1 1 1 1 2 1 2 + test1(4000, 4); // 1 2 1 2 + + rewriteMaxRetries(1); + test1(1000, 4); // 1 2 1 2 + test1(1000, 4); // 1 2 1 2 + + rewriteMaxRetries(-1); + test1(5000, 5); // 1 1 2 1 2 + test1(5000, 4); // 1 2 1 2 + + rewriteUdpPrefLimit(-1, -1); // default, no limit + test2("UDP"); + + rewriteUdpPrefLimit(10, -1); // global rules + test2("TCP"); + + rewriteUdpPrefLimit(10, 10000); // realm rules + test2("UDP"); + + rewriteUdpPrefLimit(10000, 10); // realm rules + test2("TCP"); + } + + /** + * One round of test for max_retries and timeout. + * @param timeout the expected timeout + * @param count the expected total try + */ + private static void test1(int timeout, int count) throws Exception { + String timeoutTag = "timeout=" + timeout; + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + PrintStream oldout = System.out; + System.setOut(new PrintStream(bo)); + Context c = Context.fromJAAS("client"); + System.setOut(oldout); + + String[] lines = new String(bo.toByteArray()).split("\n"); + System.out.println("----------------- TEST (" + timeout + "," + + count + ") -----------------"); + for (String line: lines) { + if (line.startsWith(">>> KDCCommunication")) { + System.out.println(line); + if (line.indexOf(timeoutTag) < 0) { + throw new Exception("Wrong timeout value"); + } + count--; + } + } + if (count != 0) { + throw new Exception("Retry count is " + count + " less"); + } + } + + /** + * One round of test for udp_preference_limit. + * @param proto the expected protocol used + */ + private static void test2(String proto) throws Exception { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + PrintStream oldout = System.out; + System.setOut(new PrintStream(bo)); + Context c = Context.fromJAAS("client"); + System.setOut(oldout); + + int count = 2; + String[] lines = new String(bo.toByteArray()).split("\n"); + System.out.println("----------------- TEST -----------------"); + for (String line: lines) { + if (line.startsWith(">>> KDCCommunication")) { + System.out.println(line); + count--; + if (line.indexOf(proto) < 0) { + throw new Exception("Wrong timeout value"); + } + } + } + if (count != 0) { + throw new Exception("Retry count is " + count + " less"); + } + } + + /** + * Set udp_preference_limit for global and realm + */ + private static void rewriteUdpPrefLimit(int global, int realm) + throws Exception { + BufferedReader fr = new BufferedReader(new FileReader(OneKDC.KRB5_CONF)); + FileWriter fw = new FileWriter("alternative-krb5.conf"); + while (true) { + String s = fr.readLine(); + if (s == null) { + break; + } + if (s.startsWith("[realms]")) { + // Reconfig global setting + if (global != -1) { + fw.write("udp_preference_limit = " + global + "\n"); + } + } else if (s.trim().startsWith("kdc = ")) { + if (realm != -1) { + // Reconfig for realm + fw.write(" udp_preference_limit = " + realm + "\n"); + } + } + fw.write(s + "\n"); + } + fr.close(); + fw.close(); + sun.security.krb5.Config.refresh(); + } + + /** + * Set max_retries and timeout value for realm. The global value is always + * 2 and 5000. + * @param value max_retries and timeout/1000 for a realm, -1 means none. + */ + private static void rewriteMaxRetries(int value) throws Exception { + BufferedReader fr = new BufferedReader(new FileReader(OneKDC.KRB5_CONF)); + FileWriter fw = new FileWriter("alternative-krb5.conf"); + while (true) { + String s = fr.readLine(); + if (s == null) { + break; + } + if (s.startsWith("[realms]")) { + // Reconfig global setting + fw.write("max_retries = 2\n"); + fw.write("kdc_timeout = 5000\n"); + } else if (s.trim().startsWith("kdc = ")) { + if (value != -1) { + // Reconfig for realm + fw.write(" max_retries = " + value + "\n"); + fw.write(" kdc_timeout = " + (value*1000) + "\n"); + } + // Add a bad KDC as the first candidate + fw.write(" kdc = localhost:33333\n"); + } + fw.write(s + "\n"); + } + fr.close(); + fw.close(); + sun.security.krb5.Config.refresh(); + } +}