8031111: fix krb5 caddr
authorweijun
Thu, 04 Jun 2015 15:29:29 +0800
changeset 30959 14e1b420cdd6
parent 30958 30ab8e4e8a17
child 30960 016d47557b45
8031111: fix krb5 caddr Reviewed-by: valeriep
jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java
jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbCred.java
jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/HostAddresses.java
jdk/test/sun/security/krb5/auto/Addresses.java
jdk/test/sun/security/krb5/auto/Forwarded.java
jdk/test/sun/security/krb5/auto/KDC.java
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java	Thu Jun 04 15:29:23 2015 +0800
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java	Thu Jun 04 15:29:29 2015 +0800
@@ -260,7 +260,11 @@
     }
 
     /**
-     * Gets all values for the specified keys.
+     * Gets all values (at least one) for the specified keys separated by
+     * a whitespace, or null if there is no such keys.
+     * The values can either be provided on a single line, or on multiple lines
+     * using the same key. When provided on a single line, the value can be
+     * comma or space separated.
      * @throws IllegalArgumentException if any of the keys is illegal
      *         (See {@link #get})
      */
@@ -270,6 +274,7 @@
         StringBuilder sb = new StringBuilder();
         boolean first = true;
         for (String s: v) {
+            s = s.replaceAll("[\\s,]+", " ");
             if (first) {
                 sb.append(s);
                 first = false;
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbCred.java	Thu Jun 04 15:29:23 2015 +0800
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbCred.java	Thu Jun 04 15:29:29 2015 +0800
@@ -34,6 +34,9 @@
 import sun.security.krb5.internal.*;
 import sun.security.krb5.internal.crypto.KeyUsage;
 import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
 import sun.security.util.DerValue;
 
 /**
@@ -76,10 +79,24 @@
         options.set(KDCOptions.FORWARDABLE, true);
 
         HostAddresses sAddrs = null;
-        // XXX Also NT_GSS_KRB5_PRINCIPAL can be a host based principal
+
         // GSSName.NT_HOSTBASED_SERVICE should display with KRB_NT_SRV_HST
-        if (server.getNameType() == PrincipalName.KRB_NT_SRV_HST)
-            sAddrs=  new HostAddresses(server);
+        if (server.getNameType() == PrincipalName.KRB_NT_SRV_HST) {
+            sAddrs = new HostAddresses(server);
+        } else if (server.getNameType() == PrincipalName.KRB_NT_UNKNOWN) {
+            // Sometimes this is also a server
+            if (server.getNameStrings().length >= 2) {
+                String host = server.getNameStrings()[1];
+                try {
+                    InetAddress[] addr = InetAddress.getAllByName(host);
+                    if (addr != null && addr.length > 0) {
+                        sAddrs = new HostAddresses(addr);
+                    }
+                } catch (UnknownHostException ioe) {
+                    // maybe we guessed wrong, let sAddrs be null
+                }
+            }
+        }
 
         KrbTgsReq tgsReq = new KrbTgsReq(options, tgt, tgService,
                                          null, null, null, null, sAddrs, null, null, null);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/HostAddresses.java	Thu Jun 04 15:29:23 2015 +0800
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/HostAddresses.java	Thu Jun 04 15:29:29 2015 +0800
@@ -31,16 +31,14 @@
 
 package sun.security.krb5.internal;
 
+import sun.security.krb5.Config;
 import sun.security.krb5.PrincipalName;
 import sun.security.krb5.KrbException;
 import sun.security.krb5.Asn1Exception;
 import sun.security.util.*;
-import java.util.Vector;
-import java.util.ArrayList;
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.UnknownHostException;
+
+import java.net.*;
+import java.util.*;
 import java.io.IOException;
 import sun.security.krb5.internal.ccache.CCacheOutputStream;
 
@@ -293,34 +291,35 @@
      */
     public static HostAddresses getLocalAddresses() throws IOException
     {
-        String hostname = null;
-        InetAddress[] inetAddresses = null;
+        Set<InetAddress> all = new LinkedHashSet<>();
         try {
-            InetAddress localHost = InetAddress.getLocalHost();
-            hostname = localHost.getHostName();
-            inetAddresses = InetAddress.getAllByName(hostname);
-            HostAddress[] hAddresses = new HostAddress[inetAddresses.length];
-            for (int i = 0; i < inetAddresses.length; i++)
-                {
-                    hAddresses[i] = new HostAddress(inetAddresses[i]);
-                }
             if (DEBUG) {
-                System.out.println(">>> KrbKdcReq local addresses for "
-                                   + hostname + " are: ");
-
-                for (int i = 0; i < inetAddresses.length; i++) {
-                    System.out.println("\n\t" + inetAddresses[i]);
-                    if (inetAddresses[i] instanceof Inet4Address)
-                        System.out.println("IPv4 address");
-                    if (inetAddresses[i] instanceof Inet6Address)
-                        System.out.println("IPv6 address");
+                System.out.println(">>> KrbKdcReq local addresses are:");
+            }
+            String extra = Config.getInstance().getAll(
+                    "libdefaults", "extra_addresses");
+            if (extra != null) {
+                for (String s: extra.split("\\s+")) {
+                    all.add(InetAddress.getByName(s));
+                    if (DEBUG) {
+                        System.out.println("   extra_addresses: "
+                                + InetAddress.getByName(s));
+                    }
                 }
             }
-            return (new HostAddresses(hAddresses));
+            for (NetworkInterface ni:
+                    Collections.list(NetworkInterface.getNetworkInterfaces())) {
+                if (DEBUG) {
+                    System.out.println("   NetworkInterface " + ni + ":");
+                    System.out.println("      "
+                            + Collections.list(ni.getInetAddresses()));
+                }
+                all.addAll(Collections.list(ni.getInetAddresses()));
+            }
+            return new HostAddresses(all.toArray(new InetAddress[all.size()]));
         } catch (Exception exc) {
             throw new IOException(exc.toString());
         }
-
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/Addresses.java	Thu Jun 04 15:29:29 2015 +0800
@@ -0,0 +1,89 @@
+/*
+ * 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 8031111
+ * @summary fix krb5 caddr
+ * @compile -XDignore.symbol.file Addresses.java
+ * @run main/othervm Addresses
+ */
+
+import sun.security.krb5.Config;
+
+import javax.security.auth.kerberos.KerberosTicket;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+
+public class Addresses {
+
+    public static void main(String[] args) throws Exception {
+
+        KDC.saveConfig(OneKDC.KRB5_CONF, new OneKDC(null),
+                "noaddresses = false",
+                "extra_addresses = 10.0.0.10, 10.0.0.11 10.0.0.12");
+        Config.refresh();
+
+        KerberosTicket ticket =
+                Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false)
+                        .s().getPrivateCredentials(KerberosTicket.class)
+                        .iterator().next();
+
+        InetAddress loopback = InetAddress.getLoopbackAddress();
+        InetAddress extra1 = InetAddress.getByName("10.0.0.10");
+        InetAddress extra2 = InetAddress.getByName("10.0.0.11");
+        InetAddress extra3 = InetAddress.getByName("10.0.0.12");
+
+        boolean loopbackFound = false;
+        boolean extra1Found = false;
+        boolean extra2Found = false;
+        boolean extra3Found = false;
+        boolean networkFound = false;
+
+        for (InetAddress ia: ticket.getClientAddresses()) {
+            System.out.println(ia);
+            if (ia.equals(loopback)) {
+                loopbackFound = true;
+                System.out.println("  loopback found");
+            } else if (ia.equals(extra1)) {
+                extra1Found = true;
+                System.out.println("  extra1 found");
+            } else if (ia.equals(extra2)) {
+                extra2Found = true;
+                System.out.println("  extra2 found");
+            } else if (ia.equals(extra3)) {
+                extra3Found = true;
+                System.out.println("  extra3 found");
+            } else if (ia instanceof Inet4Address) {
+                networkFound = true;
+                System.out.println("  another address (" + ia +
+                        "), assumed real network");
+            }
+        }
+
+        if (!loopbackFound || !networkFound
+                || !extra1Found || !extra2Found || !extra3Found ) {
+            throw new Exception();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/Forwarded.java	Thu Jun 04 15:29:29 2015 +0800
@@ -0,0 +1,51 @@
+/*
+ * 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 8031111
+ * @summary fix krb5 caddr
+ * @compile -XDignore.symbol.file Forwarded.java
+ * @run main/othervm Forwarded
+ */
+
+import sun.security.jgss.GSSUtil;
+import sun.security.krb5.internal.KDCOptions;
+import sun.security.krb5.internal.KDCReqBody;
+import sun.security.krb5.internal.TGSReq;
+
+public class Forwarded {
+
+    public static void main(String[] args) throws Exception {
+
+        new OneKDC(null).setOption(KDC.Option.CHECK_ADDRESSES, true);
+
+        Context c;
+        c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false);
+
+        c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+        c.x().requestCredDeleg(true);
+
+        c.take(new byte[0]);
+    }
+}
--- a/jdk/test/sun/security/krb5/auto/KDC.java	Thu Jun 04 15:29:23 2015 +0800
+++ b/jdk/test/sun/security/krb5/auto/KDC.java	Thu Jun 04 15:29:29 2015 +0800
@@ -205,6 +205,10 @@
          * Sensitive accounts can never be delegated.
          */
         SENSITIVE_ACCOUNTS,
+        /**
+         * If true, will check if TGS-REQ contains a non-null addresses field.
+         */
+        CHECK_ADDRESSES,
     };
 
     static {
@@ -734,6 +738,11 @@
                     bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true;
                 }
             }
+            if (options.containsKey(Option.CHECK_ADDRESSES)
+                    && body.kdcOptions.get(KDCOptions.FORWARDED)
+                    && body.addresses == null) {
+                throw new KrbException(Krb5.KDC_ERR_BADOPTION);
+            }
             if (body.kdcOptions.get(KDCOptions.FORWARDED) ||
                     etp.flags.get(Krb5.TKT_OPTS_FORWARDED)) {
                 bFlags[Krb5.TKT_OPTS_FORWARDED] = true;
@@ -800,10 +809,8 @@
                     new KerberosTime(new Date()),
                     body.from,
                     till, body.rtime,
-                    body.addresses != null  // always set caddr
-                            ? body.addresses
-                            : new HostAddresses(
-                                new InetAddress[]{InetAddress.getLocalHost()}),
+                    body.addresses != null ? body.addresses
+                            : etp.caddr,
                     null);
             EncryptionKey skey = keyForUser(service, e3, true);
             if (skey == null) {
@@ -826,10 +833,7 @@
                     body.from,
                     till, body.rtime,
                     service,
-                    body.addresses != null  // always set caddr
-                            ? body.addresses
-                            : new HostAddresses(
-                                new InetAddress[]{InetAddress.getLocalHost()})
+                    body.addresses
                     );
             EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY);
             TGSRep tgsRep = new TGSRep(null,