jdk/test/sun/security/krb5/auto/KDC.java
changeset 3046 dd50d75d88e6
parent 2942 37d9baeb7518
child 4168 1a8d21bb898c
--- a/jdk/test/sun/security/krb5/auto/KDC.java	Tue Jun 16 20:46:25 2009 +0800
+++ b/jdk/test/sun/security/krb5/auto/KDC.java	Wed Jun 17 15:26:58 2009 +0800
@@ -30,6 +30,8 @@
 import java.security.SecureRandom;
 import java.util.*;
 import java.util.concurrent.*;
+import sun.net.spi.nameservice.NameService;
+import sun.net.spi.nameservice.NameServiceDescriptor;
 import sun.security.krb5.*;
 import sun.security.krb5.internal.*;
 import sun.security.krb5.internal.ccache.CredentialsCache;
@@ -118,14 +120,16 @@
 
     // The random generator to generate random keys (including session keys)
     private static SecureRandom secureRandom = new SecureRandom();
-    // Principal db
+    // Principal db. principal -> pass
     private Map<String,char[]> passwords = new HashMap<String,char[]>();
     // Realm name
     private String realm;
+    // KDC
+    private String kdc;
+    // Service port number
+    private int port;
     // The request/response job queue
     private BlockingQueue<Job> q = new ArrayBlockingQueue<Job>(100);
-    // Service port number
-    private int port;
     // Options
     private Map<Option,Object> options = new HashMap<Option,Object>();
 
@@ -139,33 +143,21 @@
         PREAUTH_REQUIRED,
     };
 
+    static {
+        System.setProperty("sun.net.spi.nameservice.provider.1", "ns,mock");
+    }
+
     /**
      * A standalone KDC server.
-     * @param args
-     * @throws java.lang.Exception
      */
     public static void main(String[] args) throws Exception {
-        if (args.length > 0) {
-            if (args[0].equals("-help") || args[0].equals("--help")) {
-                System.out.println("Usage:");
-                System.out.println("   java " + KDC.class + "       " +
-                        "Start KDC on port 8888");
-                return;
-            }
-        }
-        String localhost = "localhost";
-        try {
-            localhost = InetAddress.getByName(localhost)
-                    .getCanonicalHostName();
-        } catch (UnknownHostException uhe) {
-            ;   // Ignore, localhost is still "localhost"
-        }
-        KDC kdc = create("RABBIT.HOLE", 8888, false);
+        KDC kdc = create("RABBIT.HOLE", "kdc.rabbit,hole", 0, false);
         kdc.addPrincipal("dummy", "bogus".toCharArray());
         kdc.addPrincipal("foo", "bar".toCharArray());
-        kdc.addPrincipalRandKey("krbtgt/" + kdc.realm);
-        kdc.addPrincipalRandKey("server/" + localhost);
-        kdc.addPrincipalRandKey("backend/" + localhost);
+        kdc.addPrincipalRandKey("krbtgt/RABBIT.HOLE");
+        kdc.addPrincipalRandKey("server/host.rabbit.hole");
+        kdc.addPrincipalRandKey("backend/host.rabbit.hole");
+        KDC.saveConfig("krb5.conf", kdc, "forwardable = true");
     }
 
     /**
@@ -175,7 +167,7 @@
      * @throws java.io.IOException for any socket creation error
      */
     public static KDC create(String realm) throws IOException {
-        return create(realm, 0, true);
+        return create(realm, "kdc." + realm.toLowerCase(), 0, true);
     }
 
     /**
@@ -187,8 +179,8 @@
      * @return the running KDC instance
      * @throws java.io.IOException for any socket creation error
      */
-    public static KDC create(String realm, int port, boolean asDaemon) throws IOException {
-        return new KDC(realm, port, asDaemon);
+    public static KDC create(String realm, String kdc, int port, boolean asDaemon) throws IOException {
+        return new KDC(realm, kdc, port, asDaemon);
     }
 
     /**
@@ -228,10 +220,7 @@
         KeyTab ktab = KeyTab.create(tab);
         for (KDC kdc: kdcs) {
             for (String name : kdc.passwords.keySet()) {
-                if (name.equals("krbtgt/" + kdc.realm)) {
-                    continue;
-                }
-                ktab.addEntry(new PrincipalName(name + "@" + kdc.realm,
+                ktab.addEntry(new PrincipalName(name,
                         name.indexOf('/') < 0 ?
                             PrincipalName.KRB_NT_UNKNOWN :
                             PrincipalName.KRB_NT_SRV_HST),
@@ -255,6 +244,9 @@
      * @param pass the password for the principal
      */
     public void addPrincipal(String user, char[] pass) {
+        if (user.indexOf('@') < 0) {
+            user = user + "@" + realm;
+        }
         passwords.put(user, pass);
     }
 
@@ -264,7 +256,7 @@
      *        form of host/f.q.d.n
      */
     public void addPrincipalRandKey(String user) {
-        passwords.put(user, randomPassword());
+        addPrincipal(user, randomPassword());
     }
 
     /**
@@ -276,6 +268,14 @@
     }
 
     /**
+     * Returns the name of kdc
+     * @return the name of kdc
+     */
+    public String getKDC() {
+        return kdc;
+    }
+
+    /**
      * Writes a krb5.conf for one or more KDC that includes KDC locations for
      * each realm and the default realm name. You can also add extra strings
      * into the file. The method should be called like:
@@ -299,7 +299,7 @@
      *
      * [realms]
      *   REALM.NAME = {
-     *     kdc = localhost:port_number
+     *     kdc = host:port_number
      *   }
      * </pre>
      *
@@ -320,10 +320,10 @@
      *
      * [realms]
      *   KDC1.NAME = {
-     *     kdc = localhost:port1
+     *     kdc = host:port1
      *   }
      *   KDC2.NAME = {
-     *     kdc = localhost:port2
+     *     kdc = host:port2
      *   }
      * </pre>
      * @param file the name of the file to write into
@@ -372,16 +372,17 @@
      * Private constructor, cannot be called outside.
      * @param realm
      */
-    private KDC(String realm) {
+    private KDC(String realm, String kdc) {
         this.realm = realm;
+        this.kdc = kdc;
     }
 
     /**
      * A constructor that starts the KDC service also.
      */
-    protected KDC(String realm, int port, boolean asDaemon)
+    protected KDC(String realm, String kdc, int port, boolean asDaemon)
             throws IOException {
-        this(realm);
+        this(realm, kdc);
         startServer(port, asDaemon);
     }
     /**
@@ -426,7 +427,11 @@
      *         the database.
      */
     private char[] getPassword(PrincipalName p) throws KrbException {
-        char[] pass = passwords.get(p.getNameString());
+        String pn = p.toString();
+        if (p.getRealmString() == null) {
+            pn = pn + "@" + getRealm();
+        }
+        char[] pass = passwords.get(pn);
         if (pass == null) {
             throw new KrbException(Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN);
         }
@@ -434,29 +439,18 @@
     }
 
     /**
-     * Returns the salt string for the principal. For normal users, the
-     * concatenation for the realm name and the sections of the principal;
-     * for krgtgt/A@B and krbtgt/B@A, always return AB (so that inter-realm
-     * principals have the same key).
+     * Returns the salt string for the principal.
      * @param p principal
      * @return the salt
      */
     private String getSalt(PrincipalName p) {
         String[] ns = p.getNameStrings();
-        if (ns[0].equals("krbtgt") && ns.length > 1) {
-            // Shared cross-realm keys must be the same
-            if (ns[1].compareTo(realm) < 0) {
-                return ns[1] + realm;
-            } else {
-                return realm + ns[1];
-            }
-        } else {
-            String s = getRealm();
-            for (String n: p.getNameStrings()) {
-                s += n;
-            }
-            return s;
+        String s = p.getRealmString();
+        if (s == null) s = getRealm();
+        for (String n: p.getNameStrings()) {
+            s += n;
         }
+        return s;
     }
 
     /**
@@ -525,14 +519,8 @@
                         EncryptedData ed = apReq.authenticator;
                         tkt = apReq.ticket;
                         etype = tkt.encPart.getEType();
-                        EncryptionKey kkey = null;
-                        if (!tkt.realm.toString().equals(realm)) {
-                            if (tkt.sname.getNameString().equals("krbtgt/" + realm)) {
-                                kkey = keyForUser(new PrincipalName("krbtgt/" + tkt.realm.toString(), realm), etype);
-                            }
-                        } else {
-                            kkey = keyForUser(tkt.sname, etype);
-                        }
+                        tkt.sname.setRealm(tkt.realm);
+                        EncryptionKey kkey = keyForUser(tkt.sname, etype);
                         byte[] bb = tkt.encPart.decrypt(kkey, KeyUsage.KU_TICKET);
                         DerInputStream derIn = new DerInputStream(bb);
                         DerValue der = derIn.getDerValue();
@@ -857,10 +845,13 @@
     /**
      * Generates a line for a KDC to put inside [realms] of krb5.conf
      * @param kdc the KDC
-     * @return REALM.NAME = { kdc = localhost:port }
+     * @return REALM.NAME = { kdc = host:port }
      */
     private static String realmLineForKDC(KDC kdc) {
-        return String.format("  %s = {\n    kdc = localhost:%d\n  }\n", kdc.realm, kdc.port);
+        return String.format("  %s = {\n    kdc = %s:%d\n  }\n",
+                kdc.realm,
+                kdc.kdc,
+                kdc.port);
     }
 
     /**
@@ -1000,4 +991,37 @@
             }
         }
     }
+
+    public static class KDCNameService implements NameServiceDescriptor {
+        @Override
+        public NameService createNameService() throws Exception {
+            NameService ns = new NameService() {
+                @Override
+                public InetAddress[] lookupAllHostAddr(String host)
+                        throws UnknownHostException {
+                    // Everything is localhost
+                    return new InetAddress[]{
+                        InetAddress.getByAddress(host, new byte[]{127,0,0,1})
+                    };
+                }
+                @Override
+                public String getHostByAddr(byte[] addr)
+                        throws UnknownHostException {
+                    // No reverse lookup, PrincipalName use original string
+                    throw new UnknownHostException();
+                }
+            };
+            return ns;
+        }
+
+        @Override
+        public String getProviderName() {
+            return "mock";
+        }
+
+        @Override
+        public String getType() {
+            return "ns";
+        }
+    }
 }