--- 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";
+ }
+ }
}