diff -r cdfc2f549bbc -r dd50d75d88e6 jdk/test/sun/security/krb5/auto/KDC.java --- 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 passwords = new HashMap(); // Realm name private String realm; + // KDC + private String kdc; + // Service port number + private int port; // The request/response job queue private BlockingQueue q = new ArrayBlockingQueue(100); - // Service port number - private int port; // Options private Map options = new HashMap(); @@ -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 * } * * @@ -320,10 +320,10 @@ * * [realms] * KDC1.NAME = { - * kdc = localhost:port1 + * kdc = host:port1 * } * KDC2.NAME = { - * kdc = localhost:port2 + * kdc = host:port2 * } * * @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"; + } + } }