]+");
System.exit(1);
}
File workDir = new File(args[0]);
if (!workDir.exists()) {
- throw new RuntimeException("Specified work directory does not exists: " + workDir.getAbsolutePath());
+ throw new RuntimeException("Specified work directory does not exists: "
+ + workDir.getAbsolutePath());
}
Properties conf = createConf();
File file = new File(args[1]);
if (!file.exists()) {
- throw new RuntimeException("Specified configuration does not exists: " + file.getAbsolutePath());
+ throw new RuntimeException("Specified configuration does not exists: "
+ + file.getAbsolutePath());
}
Properties userConf = new Properties();
InputStreamReader r = null;
@@ -161,7 +117,8 @@ public static void main(String[] args) throws Exception {
System.out.println("Standalone MiniKdc Running");
System.out.println("---------------------------------------------------");
System.out.println(" Realm : " + miniKdc.getRealm());
- System.out.println(" Running at : " + miniKdc.getHost() + ":" + miniKdc.getHost());
+ System.out.println(" Running at : " + miniKdc.getHost() + ":" +
+ miniKdc.getHost());
System.out.println(" krb5conf : " + krb5conf);
System.out.println();
System.out.println(" created keytab : " + keytabFile);
@@ -177,7 +134,8 @@ public void run() {
}
});
} else {
- throw new RuntimeException("Cannot rename KDC's krb5conf to " + krb5conf.getAbsolutePath());
+ throw new RuntimeException("Cannot rename KDC's krb5conf to "
+ + krb5conf.getAbsolutePath());
}
}
@@ -223,7 +181,6 @@ public void run() {
*
* The returned configuration is a copy, it can be customized before using
* it to create a MiniKdc.
- *
* @return a MiniKdc default configuration.
*/
public static Properties createConf() {
@@ -231,34 +188,37 @@ public static Properties createConf() {
}
private Properties conf;
- private DirectoryService ds;
- private KdcServer kdc;
+ private SimpleKdcServer simpleKdc;
private int port;
private String realm;
private File workDir;
private File krb5conf;
+ private String transport;
+ private boolean krb5Debug;
+ public void setTransport(String transport) {
+ this.transport = transport;
+ }
/**
* Creates a MiniKdc.
*
- * @param conf
- * MiniKdc configuration.
- * @param workDir
- * working directory, it should be the build directory. Under
- * this directory an ApacheDS working directory will be created,
- * this directory will be deleted when the MiniKdc stops.
- * @throws Exception
- * thrown if the MiniKdc could not be created.
+ * @param conf MiniKdc configuration.
+ * @param workDir working directory, it should be the build directory. Under
+ * this directory an ApacheDS working directory will be created, this
+ * directory will be deleted when the MiniKdc stops.
+ * @throws Exception thrown if the MiniKdc could not be created.
*/
public MiniKdc(Properties conf, File workDir) throws Exception {
if (!conf.keySet().containsAll(PROPERTIES)) {
Set missingProperties = new HashSet(PROPERTIES);
missingProperties.removeAll(conf.keySet());
- throw new IllegalArgumentException("Missing configuration properties: " + missingProperties);
+ throw new IllegalArgumentException("Missing configuration properties: "
+ + missingProperties);
}
this.workDir = new File(workDir, Long.toString(System.currentTimeMillis()));
- if (!workDir.exists() && !workDir.mkdirs()) {
- throw new RuntimeException("Cannot create directory " + workDir);
+ if (!this.workDir.exists()
+ && !this.workDir.mkdirs()) {
+ throw new RuntimeException("Cannot create directory " + this.workDir);
}
LOG.info("Configuration:");
LOG.info("---------------------------------------------------------------");
@@ -268,14 +228,10 @@ public MiniKdc(Properties conf, File workDir) throws Exception {
LOG.info("---------------------------------------------------------------");
this.conf = conf;
port = Integer.parseInt(conf.getProperty(KDC_PORT));
- if (port == 0) {
- ServerSocket ss = new ServerSocket(0, 1, InetAddress.getByName(conf.getProperty(KDC_BIND_ADDRESS)));
- port = ss.getLocalPort();
- ss.close();
- }
- String orgName = conf.getProperty(ORG_NAME);
+ String orgName= conf.getProperty(ORG_NAME);
String orgDomain = conf.getProperty(ORG_DOMAIN);
- realm = orgName.toUpperCase(Locale.ENGLISH) + "." + orgDomain.toUpperCase(Locale.ENGLISH);
+ realm = orgName.toUpperCase(Locale.ENGLISH) + "."
+ + orgDomain.toUpperCase(Locale.ENGLISH);
}
/**
@@ -306,203 +262,103 @@ public String getRealm() {
}
public File getKrb5conf() {
+ krb5conf = new File(System.getProperty(JAVA_SECURITY_KRB5_CONF));
return krb5conf;
}
/**
* Starts the MiniKdc.
*
- * @throws Exception
- * thrown if the MiniKdc could not be started.
+ * @throws Exception thrown if the MiniKdc could not be started.
*/
public synchronized void start() throws Exception {
- if (kdc != null) {
+ if (simpleKdc != null) {
throw new RuntimeException("Already started");
}
- initDirectoryService();
- initKDCServer();
+ simpleKdc = new SimpleKdcServer();
+ prepareKdcServer();
+ simpleKdc.init();
+ resetDefaultRealm();
+ simpleKdc.start();
+ LOG.info("MiniKdc stated.");
}
- private void initDirectoryService() throws Exception {
- ds = new DefaultDirectoryService();
- ds.setInstanceLayout(new InstanceLayout(workDir));
-
- CacheService cacheService = new CacheService();
- ds.setCacheService(cacheService);
-
- // first load the schema
- InstanceLayout instanceLayout = ds.getInstanceLayout();
- File schemaPartitionDirectory = new File(instanceLayout.getPartitionsDirectory(), "schema");
- SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor(instanceLayout.getPartitionsDirectory());
- extractor.extractOrCopy();
-
- SchemaLoader loader = new LdifSchemaLoader(schemaPartitionDirectory);
- SchemaManager schemaManager = new DefaultSchemaManager(loader);
- schemaManager.loadAllEnabled();
- ds.setSchemaManager(schemaManager);
- // Init the LdifPartition with schema
- LdifPartition schemaLdifPartition = new LdifPartition(schemaManager);
- schemaLdifPartition.setPartitionPath(schemaPartitionDirectory.toURI());
-
- // The schema partition
- SchemaPartition schemaPartition = new SchemaPartition(schemaManager);
- schemaPartition.setWrappedPartition(schemaLdifPartition);
- ds.setSchemaPartition(schemaPartition);
-
- JdbmPartition systemPartition = new JdbmPartition(ds.getSchemaManager());
- systemPartition.setId("system");
- systemPartition.setPartitionPath(
- new File(ds.getInstanceLayout().getPartitionsDirectory(), systemPartition.getId()).toURI());
- systemPartition.setSuffixDn(new Dn(ServerDNConstants.SYSTEM_DN));
- systemPartition.setSchemaManager(ds.getSchemaManager());
- ds.setSystemPartition(systemPartition);
-
- ds.getChangeLog().setEnabled(false);
- ds.setDenormalizeOpAttrsEnabled(true);
- ds.addLast(new KeyDerivationInterceptor());
-
- // create one partition
- String orgName = conf.getProperty(ORG_NAME).toLowerCase(Locale.ENGLISH);
- String orgDomain = conf.getProperty(ORG_DOMAIN).toLowerCase(Locale.ENGLISH);
-
- JdbmPartition partition = new JdbmPartition(ds.getSchemaManager());
- partition.setId(orgName);
- partition.setPartitionPath(new File(ds.getInstanceLayout().getPartitionsDirectory(), orgName).toURI());
- partition.setSuffixDn(new Dn("dc=" + orgName + ",dc=" + orgDomain));
- ds.addPartition(partition);
- // indexes
- Set> indexedAttributes = new HashSet>();
- indexedAttributes.add(new JdbmIndex("objectClass", false));
- indexedAttributes.add(new JdbmIndex("dc", false));
- indexedAttributes.add(new JdbmIndex("ou", false));
- partition.setIndexedAttributes(indexedAttributes);
-
- // And start the ds
- ds.setInstanceId(conf.getProperty(INSTANCE));
- ds.startup();
- // context entry, after ds.startup()
- Dn dn = new Dn("dc=" + orgName + ",dc=" + orgDomain);
- Entry entry = ds.newEntry(dn);
- entry.add("objectClass", "top", "domain");
- entry.add("dc", orgName);
- ds.getAdminSession().add(entry);
+ private void resetDefaultRealm() throws IOException {
+ InputStream templateResource = new FileInputStream(
+ getKrb5conf().getAbsolutePath());
+ String content = IOUtil.readInput(templateResource);
+ content = content.replaceAll("default_realm = .*\n",
+ "default_realm = " + getRealm() + "\n");
+ IOUtil.writeFile(content, getKrb5conf());
}
- private void initKDCServer() throws Exception {
- String orgName = conf.getProperty(ORG_NAME);
- String orgDomain = conf.getProperty(ORG_DOMAIN);
- String bindAddress = conf.getProperty(KDC_BIND_ADDRESS);
- final Map map = new HashMap();
- map.put("0", orgName.toLowerCase(Locale.ENGLISH));
- map.put("1", orgDomain.toLowerCase(Locale.ENGLISH));
- map.put("2", orgName.toUpperCase(Locale.ENGLISH));
- map.put("3", orgDomain.toUpperCase(Locale.ENGLISH));
- map.put("4", bindAddress);
-
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- InputStream is1 = cl.getResourceAsStream("data/kerberos/minikdc.ldiff");
-
- SchemaManager schemaManager = ds.getSchemaManager();
- LdifReader reader = null;
-
- try {
- final String content = StrSubstitutor.replace(IOUtils.toString(is1), map);
- reader = new LdifReader(new StringReader(content));
-
- for (LdifEntry ldifEntry : reader) {
- ds.getAdminSession().add(new DefaultEntry(schemaManager, ldifEntry.getEntry()));
- }
- } finally {
- IOUtils.closeQuietly(reader);
- IOUtils.closeQuietly(is1);
- }
-
- KerberosConfig kerberosConfig = new KerberosConfig();
- kerberosConfig.setMaximumRenewableLifetime(Long.parseLong(conf.getProperty(MAX_RENEWABLE_LIFETIME)));
- kerberosConfig.setMaximumTicketLifetime(Long.parseLong(conf.getProperty(MAX_TICKET_LIFETIME)));
- kerberosConfig.setSearchBaseDn(String.format("dc=%s,dc=%s", orgName, orgDomain));
- kerberosConfig.setPaEncTimestampRequired(false);
- kdc = new KdcServer(kerberosConfig);
- kdc.setDirectoryService(ds);
-
+ private void prepareKdcServer() throws Exception {
// transport
- String transport = conf.getProperty(TRANSPORT);
- if (transport.trim().equals("TCP")) {
- kdc.addTransports(new TcpTransport(bindAddress, port, 3, 50));
- } else if (transport.trim().equals("UDP")) {
- kdc.addTransports(new UdpTransport(port));
- } else {
- throw new IllegalArgumentException("Invalid transport: " + transport);
+ simpleKdc.setWorkDir(workDir);
+ simpleKdc.setKdcHost(getHost());
+ simpleKdc.setKdcRealm(realm);
+ if (transport == null) {
+ transport = conf.getProperty(TRANSPORT);
}
- kdc.setServiceName(conf.getProperty(INSTANCE));
- kdc.start();
-
- StringBuilder sb = new StringBuilder();
- InputStream is2 = cl.getResourceAsStream("data/kerberos/minikdc-krb5.conf");
-
- BufferedReader r = null;
-
- try {
- r = new BufferedReader(new InputStreamReader(is2, Charsets.UTF_8));
- String line = r.readLine();
-
- while (line != null) {
- sb.append(line).append("{3}");
- line = r.readLine();
- }
- } finally {
- IOUtils.closeQuietly(r);
- IOUtils.closeQuietly(is2);
+ if (port == 0) {
+ port = NetworkUtil.getServerPort();
}
-
- krb5conf = new File(workDir, "krb5.conf").getAbsoluteFile();
- FileUtils.writeStringToFile(krb5conf, MessageFormat.format(sb.toString(), getRealm(), getHost(),
- Integer.toString(getPort()), System.getProperty("line.separator")));
- System.setProperty(JAVA_SECURITY_KRB5_CONF, krb5conf.getAbsolutePath());
-
- System.setProperty(SUN_SECURITY_KRB5_DEBUG, conf.getProperty(DEBUG, "false"));
-
- // refresh the config
- Class> classRef;
- if (System.getProperty("java.vendor").contains("IBM")) {
- classRef = Class.forName("com.ibm.security.krb5.internal.Config");
+ if (transport != null) {
+ if (transport.trim().equals("TCP")) {
+ simpleKdc.setKdcTcpPort(port);
+ simpleKdc.setAllowUdp(false);
+ } else if (transport.trim().equals("UDP")) {
+ simpleKdc.setKdcUdpPort(port);
+ simpleKdc.setAllowTcp(false);
+ } else {
+ throw new IllegalArgumentException("Invalid transport: " + transport);
+ }
} else {
- classRef = Class.forName("sun.security.krb5.Config");
+ throw new IllegalArgumentException("Need to set transport!");
+ }
+ simpleKdc.getKdcConfig().setString(KdcConfigKey.KDC_SERVICE_NAME,
+ conf.getProperty(INSTANCE));
+ if (conf.getProperty(DEBUG) != null) {
+ krb5Debug = getAndSet(SUN_SECURITY_KRB5_DEBUG, conf.getProperty(DEBUG));
}
- Method refreshMethod = classRef.getMethod("refresh", new Class[0]);
- refreshMethod.invoke(classRef, new Object[0]);
-
- LOG.info("MiniKdc listening at port: {}", getPort());
- LOG.info("MiniKdc setting JVM krb5.conf to: {}", krb5conf.getAbsolutePath());
}
/**
* Stops the MiniKdc
*/
public synchronized void stop() {
- if (kdc != null) {
- System.getProperties().remove(JAVA_SECURITY_KRB5_CONF);
- System.getProperties().remove(SUN_SECURITY_KRB5_DEBUG);
- kdc.stop();
+ if (simpleKdc != null) {
try {
- ds.shutdown();
- } catch (Exception ex) {
- LOG.error("Could not shutdown ApacheDS properly: {}", ex.toString(), ex);
+ simpleKdc.stop();
+ } catch (KrbException e) {
+ e.printStackTrace();
+ } finally {
+ if(conf.getProperty(DEBUG) != null) {
+ System.setProperty(SUN_SECURITY_KRB5_DEBUG,
+ Boolean.toString(krb5Debug));
+ }
}
}
delete(workDir);
+ try {
+ // Will be fixed in next Kerby version.
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ LOG.info("MiniKdc stopped.");
}
private void delete(File f) {
if (f.isFile()) {
- if (!f.delete()) {
+ if (! f.delete()) {
LOG.warn("WARNING: cannot delete file " + f.getAbsolutePath());
}
} else {
- for (File c : f.listFiles()) {
+ for (File c: f.listFiles()) {
delete(c);
}
- if (!f.delete()) {
+ if (! f.delete()) {
LOG.warn("WARNING: cannot delete directory " + f.getAbsolutePath());
}
}
@@ -511,56 +367,45 @@ private void delete(File f) {
/**
* Creates a principal in the KDC with the specified user and password.
*
- * @param principal
- * principal name, do not include the domain.
- * @param password
- * password.
- * @throws Exception
- * thrown if the principal could not be created.
+ * @param principal principal name, do not include the domain.
+ * @param password password.
+ * @throws Exception thrown if the principal could not be created.
*/
- public synchronized void createPrincipal(String principal, String password) throws Exception {
- String orgName = conf.getProperty(ORG_NAME);
- String orgDomain = conf.getProperty(ORG_DOMAIN);
- String baseDn = "ou=users,dc=" + orgName.toLowerCase(Locale.ENGLISH) + ",dc="
- + orgDomain.toLowerCase(Locale.ENGLISH);
- String content = "dn: uid=" + principal + "," + baseDn + "\n" + "objectClass: top\n" + "objectClass: person\n"
- + "objectClass: inetOrgPerson\n" + "objectClass: krb5principal\n" + "objectClass: krb5kdcentry\n"
- + "cn: " + principal + "\n" + "sn: " + principal + "\n" + "uid: " + principal + "\n" + "userPassword: "
- + password + "\n" + "krb5PrincipalName: " + principal + "@" + getRealm() + "\n"
- + "krb5KeyVersionNumber: 0";
-
- for (LdifEntry ldifEntry : new LdifReader(new StringReader(content))) {
- ds.getAdminSession().add(new DefaultEntry(ds.getSchemaManager(), ldifEntry.getEntry()));
- }
+ public synchronized void createPrincipal(String principal, String password)
+ throws Exception {
+ simpleKdc.createPrincipal(principal, password);
}
/**
* Creates multiple principals in the KDC and adds them to a keytab file.
*
- * @param keytabFile
- * keytab file to add the created principal.s
- * @param principals
- * principals to add to the KDC, do not include the domain.
- * @throws Exception
- * thrown if the principals or the keytab file could not be
- * created.
+ * @param keytabFile keytab file to add the created principals.
+ * @param principals principals to add to the KDC, do not include the domain.
+ * @throws Exception thrown if the principals or the keytab file could not be
+ * created.
*/
- public void createPrincipal(File keytabFile, String... principals) throws Exception {
- String generatedPassword = UUID.randomUUID().toString();
- Keytab keytab = new Keytab();
- List entries = new ArrayList();
+ public synchronized void createPrincipal(File keytabFile,
+ String ... principals)
+ throws Exception {
+ simpleKdc.createPrincipals(principals);
+ if (keytabFile.exists() && !keytabFile.delete()) {
+ LOG.error("Failed to delete keytab file: " + keytabFile);
+ }
for (String principal : principals) {
- createPrincipal(principal, generatedPassword);
- principal = principal + "@" + getRealm();
- KerberosTime timestamp = new KerberosTime();
- for (Map.Entry entry : KerberosKeyFactory
- .getKerberosKeys(principal, generatedPassword).entrySet()) {
- EncryptionKey ekey = entry.getValue();
- byte keyVersion = (byte) ekey.getKeyVersion();
- entries.add(new KeytabEntry(principal, 1L, timestamp, keyVersion, ekey));
- }
+ simpleKdc.getKadmin().exportKeytab(keytabFile, principal);
}
- keytab.setEntries(entries);
- keytab.write(keytabFile);
}
-}
+
+ /**
+ * Set the System property; return the old value for caching.
+ *
+ * @param sysprop property
+ * @param debug true or false
+ * @return the previous value
+ */
+ private boolean getAndSet(String sysprop, String debug) {
+ boolean old = Boolean.getBoolean(sysprop);
+ System.setProperty(sysprop, debug);
+ return old;
+ }
+}
\ No newline at end of file