jdk/test/sun/security/krb5/auto/MaxRetries.java
changeset 43880 b5015f742ba6
parent 43879 a6dc784b18a8
parent 43854 76c52ad1e6c7
child 43881 4d99ca794b88
equal deleted inserted replaced
43879:a6dc784b18a8 43880:b5015f742ba6
     1 /*
       
     2  * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 /*
       
    25  * @test
       
    26  * @bug 6844193
       
    27  * @compile -XDignore.symbol.file MaxRetries.java
       
    28  * @run main/othervm/timeout=300 MaxRetries
       
    29  * @summary support max_retries in krb5.conf
       
    30  */
       
    31 
       
    32 import javax.security.auth.login.LoginException;
       
    33 import java.io.*;
       
    34 import java.net.DatagramSocket;
       
    35 import java.security.Security;
       
    36 
       
    37 public class MaxRetries {
       
    38 
       
    39     static int idlePort = -1;
       
    40     static CommMatcher cm = new CommMatcher();
       
    41 
       
    42     public static void main(String[] args)
       
    43             throws Exception {
       
    44 
       
    45         System.setProperty("sun.security.krb5.debug", "true");
       
    46         OneKDC kdc = new OneKDC(null).writeJAASConf();
       
    47 
       
    48         // An idle UDP socket to prevent PortUnreachableException
       
    49         DatagramSocket ds = new DatagramSocket();
       
    50         idlePort = ds.getLocalPort();
       
    51 
       
    52         cm.addPort(idlePort);
       
    53         cm.addPort(kdc.getPort());
       
    54 
       
    55         System.setProperty("java.security.krb5.conf", "alternative-krb5.conf");
       
    56 
       
    57         Security.setProperty("krb5.kdc.bad.policy", "trylast");
       
    58 
       
    59         // We always make the real timeout to be 1 second
       
    60         BadKdc.setRatio(0.25f);
       
    61         rewriteMaxRetries(4);
       
    62 
       
    63         // Explanation: In this case, max_retries=4 and timeout=4s.
       
    64         // For AS-REQ without preauth, we will see 4 4s timeout on kdc#1
       
    65         // ("a4" repeat 4 times), and one 4s timeout on kdc#2 ("b4"). For
       
    66         // AS-REQ with preauth, one 4s timeout on kdc#2 (second "b4").
       
    67         // we tolerate 4 real timeout on kdc#2, so make it "(b4){2,6}".
       
    68         test1("a4a4a4a4b4b4", "a4a4a4a4(b4){2,6}");
       
    69         test1("b4b4", "(b4){2,6}");
       
    70 
       
    71         BadKdc.setRatio(1f);
       
    72         rewriteMaxRetries(1);
       
    73         // Explanation: Since max_retries=1 only, we could fail in 1st or 2nd
       
    74         // AS-REQ to kdc#2.
       
    75         String actual = test1("a1b1b1", "(a1b1b1|a1b1x|a1b1b1x)");
       
    76         if (actual.endsWith("x")) {
       
    77             // If 1st attempt fails, all bads are back available
       
    78             test1("a1b1b1", "(a1b1b1|a1b1x|a1b1b1x)");
       
    79         } else {
       
    80             test1("b1b1", "(b1b1|b1x|b1b1x)");
       
    81         }
       
    82 
       
    83         BadKdc.setRatio(0.2f);
       
    84         rewriteMaxRetries(-1);
       
    85         test1("a5a5a5b5b5", "a5a5a5(b5){2,4}");
       
    86         test1("b5b5", "(b5){2,4}");
       
    87 
       
    88         BadKdc.setRatio(0.25f);
       
    89         Security.setProperty("krb5.kdc.bad.policy",
       
    90                 "tryless:1,1000");
       
    91         rewriteMaxRetries(4);
       
    92         test1("a4a4a4a4b4a4b4", "a4a4a4a4(b4){1,3}a4(b4){1,3}");
       
    93         test1("a4b4a4b4", "a4(b4){1,3}a4(b4){1,3}");
       
    94 
       
    95         BadKdc.setRatio(1f);
       
    96         rewriteMaxRetries(1);
       
    97         actual = test1("a1b1a1b1", "(a1b1|a1b1x|a1b1a1b1|a1b1a1b1x)");
       
    98         if (actual.endsWith("x")) {
       
    99             test1("a1b1a1b1", "(a1b1|a1b1x|a1b1a1b1|a1b1a1b1x)");
       
   100         } else {
       
   101             test1("a1b1a1b1", "(a1b1|a1b1x|a1b1a1b1|a1b1a1b1x)");
       
   102         }
       
   103 
       
   104         BadKdc.setRatio(.2f);
       
   105         rewriteMaxRetries(-1);
       
   106         test1("a5a5a5b5a5b5", "a5a5a5(b5){1,2}a5(b5){1,2}");
       
   107         test1("a5b5a5b5", "a5(b5){1,2}a5(b5){1,2}");
       
   108 
       
   109         BadKdc.setRatio(1f);
       
   110         rewriteMaxRetries(2);
       
   111         if (BadKdc.toReal(2000) > 1000) {
       
   112             // Explanation: if timeout is longer than 1s in tryLess,
       
   113             // we will see "a1" at 2nd kdc#1 access
       
   114             test1("a2a2b2a1b2", "a2a2(b2){1,2}a1(b2){1,2}");
       
   115         } else {
       
   116             test1("a2a2b2a2b2", "a2a2(b2){1,2}a2(b2){1,2}");
       
   117         }
       
   118 
       
   119         BadKdc.setRatio(1f);
       
   120 
       
   121         rewriteUdpPrefLimit(-1, -1);    // default, no limit
       
   122         test2("UDP");
       
   123 
       
   124         rewriteUdpPrefLimit(10, -1);    // global rules
       
   125         test2("TCP");
       
   126 
       
   127         rewriteUdpPrefLimit(10, 10000); // realm rules
       
   128         test2("UDP");
       
   129 
       
   130         rewriteUdpPrefLimit(10000, 10); // realm rules
       
   131         test2("TCP");
       
   132 
       
   133         ds.close();
       
   134     }
       
   135 
       
   136     /**
       
   137      * One round of test for max_retries and timeout.
       
   138      *
       
   139      * @param exact the expected exact match, where no timeout
       
   140      *              happens for real KDCs
       
   141      * @param relaxed the expected relaxed match, where some timeout
       
   142      *                could happen for real KDCs
       
   143      * @return the actual result
       
   144      */
       
   145     private static String test1(String exact, String relaxed) throws Exception {
       
   146         ByteArrayOutputStream bo = new ByteArrayOutputStream();
       
   147         PrintStream oldout = System.out;
       
   148         System.setOut(new PrintStream(bo));
       
   149         boolean failed = false;
       
   150         long start = System.nanoTime();
       
   151         try {
       
   152             Context c = Context.fromJAAS("client");
       
   153         } catch (LoginException e) {
       
   154             failed = true;
       
   155         }
       
   156         System.setOut(oldout);
       
   157 
       
   158         String[] lines = new String(bo.toByteArray()).split("\n");
       
   159         System.out.println("----------------- TEST (" + exact
       
   160                 + ") -----------------");
       
   161 
       
   162         // Result, a series of timeout + kdc#
       
   163         StringBuilder sb = new StringBuilder();
       
   164         for (String line: lines) {
       
   165             if (cm.match(line)) {
       
   166                 System.out.println(line);
       
   167                 sb.append(cm.kdc()).append(cm.timeout());
       
   168             }
       
   169         }
       
   170         if (failed) {
       
   171             sb.append("x");
       
   172         }
       
   173         System.out.println("Time: " + (System.nanoTime() - start) / 1000000000d);
       
   174         String actual = sb.toString();
       
   175         System.out.println("Actual: " + actual);
       
   176         if (actual.equals(exact)) {
       
   177             System.out.println("Exact match: " + exact);
       
   178         } else if (actual.matches(relaxed)) {
       
   179             System.out.println("!!!! Tolerant match: " + relaxed);
       
   180         } else {
       
   181             throw new Exception("Match neither " + exact + " nor " + relaxed);
       
   182         }
       
   183         return actual;
       
   184     }
       
   185 
       
   186     /**
       
   187      * One round of test for udp_preference_limit.
       
   188      * @param proto the expected protocol used
       
   189      */
       
   190     private static void test2(String proto) throws Exception {
       
   191         ByteArrayOutputStream bo = new ByteArrayOutputStream();
       
   192         PrintStream oldout = System.out;
       
   193         System.setOut(new PrintStream(bo));
       
   194         Context c = Context.fromJAAS("client");
       
   195         System.setOut(oldout);
       
   196 
       
   197         int count = 2;
       
   198         String[] lines = new String(bo.toByteArray()).split("\n");
       
   199         System.out.println("----------------- TEST -----------------");
       
   200         for (String line: lines) {
       
   201             if (cm.match(line)) {
       
   202                 System.out.println(line);
       
   203                 count--;
       
   204                 if (!cm.protocol().equals(proto)) {
       
   205                     throw new Exception("Wrong protocol value");
       
   206                 }
       
   207             }
       
   208         }
       
   209         if (count != 0) {
       
   210             throw new Exception("Retry count is " + count + " less");
       
   211         }
       
   212     }
       
   213 
       
   214     /**
       
   215      * Set udp_preference_limit for global and realm
       
   216      */
       
   217     private static void rewriteUdpPrefLimit(int global, int realm)
       
   218             throws Exception {
       
   219         BufferedReader fr = new BufferedReader(new FileReader(OneKDC.KRB5_CONF));
       
   220         FileWriter fw = new FileWriter("alternative-krb5.conf");
       
   221         while (true) {
       
   222             String s = fr.readLine();
       
   223             if (s == null) {
       
   224                 break;
       
   225             }
       
   226             if (s.startsWith("[realms]")) {
       
   227                 // Reconfig global setting
       
   228                 fw.write("kdc_timeout = 5000\n");
       
   229                 if (global != -1) {
       
   230                     fw.write("udp_preference_limit = " + global + "\n");
       
   231                 }
       
   232             } else if (s.trim().startsWith("kdc = ")) {
       
   233                 if (realm != -1) {
       
   234                     // Reconfig for realm
       
   235                     fw.write("    udp_preference_limit = " + realm + "\n");
       
   236                 }
       
   237             }
       
   238             fw.write(s + "\n");
       
   239         }
       
   240         fr.close();
       
   241         fw.close();
       
   242         sun.security.krb5.Config.refresh();
       
   243     }
       
   244 
       
   245     /**
       
   246      * Set max_retries and timeout value for realm. The global value is always
       
   247      * 3 and 5000.
       
   248      *
       
   249      * @param value max_retries and timeout/1000 for a realm, -1 means none.
       
   250      */
       
   251     private static void rewriteMaxRetries(int value) throws Exception {
       
   252         BufferedReader fr = new BufferedReader(new FileReader(OneKDC.KRB5_CONF));
       
   253         FileWriter fw = new FileWriter("alternative-krb5.conf");
       
   254         while (true) {
       
   255             String s = fr.readLine();
       
   256             if (s == null) {
       
   257                 break;
       
   258             }
       
   259             if (s.startsWith("[realms]")) {
       
   260                 // Reconfig global setting
       
   261                 fw.write("max_retries = 3\n");
       
   262                 fw.write("kdc_timeout = " + BadKdc.toReal(5000) + "\n");
       
   263             } else if (s.trim().startsWith("kdc = ")) {
       
   264                 if (value != -1) {
       
   265                     // Reconfig for realm
       
   266                     fw.write("    max_retries = " + value + "\n");
       
   267                     fw.write("    kdc_timeout = " + BadKdc.toReal(value*1000) + "\n");
       
   268                 }
       
   269                 // Add a bad KDC as the first candidate
       
   270                 fw.write("    kdc = localhost:" + idlePort + "\n");
       
   271             }
       
   272             fw.write(s + "\n");
       
   273         }
       
   274         fr.close();
       
   275         fw.close();
       
   276         sun.security.krb5.Config.refresh();
       
   277     }
       
   278 }