You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by dr...@apache.org on 2015/01/10 14:31:01 UTC

[17/42] directory-kerberos git commit: Initially import Haox codebase (https://github.com/drankye/haox)

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/httpclient/contrib/ssl/TestHttpclientContrib.java
----------------------------------------------------------------------
diff --git a/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/httpclient/contrib/ssl/TestHttpclientContrib.java b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/httpclient/contrib/ssl/TestHttpclientContrib.java
new file mode 100644
index 0000000..572dae6
--- /dev/null
+++ b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/httpclient/contrib/ssl/TestHttpclientContrib.java
@@ -0,0 +1,42 @@
+package org.apache.commons.httpclient.contrib.ssl;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+
+import org.apache.commons.httpclient.protocol.Protocol;
+import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
+
+import java.io.File;
+import java.net.URL;
+
+public class TestHttpclientContrib {
+
+    @Test
+    public void theTest() throws Exception {
+        registerCerts();
+    }
+
+    public static void registerCerts() throws Exception {
+        File keyFile = new File("samples/keystores/Sun.jks.ks");
+        File trustFile = new File("samples/cacerts-with-78-entries.jks");
+        URL ks = keyFile.toURI().toURL();
+        URL ts = trustFile.toURI().toURL();
+
+        AuthSSLProtocolSocketFactory sf;
+        sf = new AuthSSLProtocolSocketFactory(ks, "changeit", ts, "changeit");
+        sf.setCheckHostname(false);
+
+        // There should be 78 certs in this trust-chain.
+        assertEquals(78, sf.getTrustChain().getCertificates().size());
+
+        TrustSSLProtocolSocketFactory tf;
+        tf = new TrustSSLProtocolSocketFactory(trustFile.getAbsolutePath(), "changeit".toCharArray());
+        tf.setCheckHostname(false);
+
+        String scheme1 = "https-test1";
+        Protocol.registerProtocol(scheme1, new Protocol(scheme1, (ProtocolSocketFactory) sf, 443));
+        String scheme2 = "https-test2";
+        Protocol.registerProtocol(scheme2, new Protocol(scheme2, (ProtocolSocketFactory) tf, 443));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/JUnitConfig.java
----------------------------------------------------------------------
diff --git a/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/JUnitConfig.java b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/JUnitConfig.java
new file mode 100644
index 0000000..2318737
--- /dev/null
+++ b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/JUnitConfig.java
@@ -0,0 +1,46 @@
+package org.apache.commons.ssl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Properties;
+
+public class JUnitConfig {
+
+    public final static String TEST_HOME;
+
+    static {
+        String home = "";
+        File f = new File(System.getProperty("user.home") + "/.commons-ssl.test.properties");
+        if (f.exists()) {
+            Properties p = new Properties();
+
+            boolean loaded = false;
+            FileInputStream fin = null;
+            try {
+                fin = new FileInputStream(f);
+                p.load(fin);
+                loaded = true;
+            } catch (IOException ioe) {
+                System.err.println("Failed to load: " + f);
+            } finally {
+                if (fin != null) {
+                    try {
+                        fin.close();
+                    } catch (IOException ioe) {
+                        System.err.println("Failed to close: " + f);
+                    }
+                }
+            }
+
+            if (loaded) {
+                home = p.getProperty("commons-ssl.home");
+                if (!home.endsWith("/")) {
+                    home = home + "/";
+                }
+            }
+        }
+        TEST_HOME = home;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestBase64.java
----------------------------------------------------------------------
diff --git a/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestBase64.java b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestBase64.java
new file mode 100644
index 0000000..4b29554
--- /dev/null
+++ b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestBase64.java
@@ -0,0 +1,89 @@
+package org.apache.commons.ssl;
+
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.util.Arrays;
+import java.util.Random;
+
+
+public class TestBase64 {
+
+    @Test
+    public void testOrigBase64() throws Exception {
+        Random random = new Random();
+        for (int i = 0; i < 4567; i++) {
+            byte[] buf = new byte[i];
+            random.nextBytes(buf);
+            byte[] enc = Base64.encodeBase64(buf);
+            ByteArrayInputStream in = new ByteArrayInputStream(enc);
+            enc = Util.streamToBytes(in);
+            byte[] dec = Base64.decodeBase64(enc);
+            boolean result = Arrays.equals(buf, dec);
+            if (!result) {
+                System.out.println();
+                System.out.println("testOrigBase64 Failed on : " + i);
+            }
+            assertTrue(result);
+        }
+        for (int i = 5; i < 50; i++) {
+            int testSize = (i * 1000) + 123;
+            byte[] buf = new byte[testSize];
+            random.nextBytes(buf);
+            byte[] enc = Base64.encodeBase64(buf);
+            ByteArrayInputStream in = new ByteArrayInputStream(enc);
+            enc = Util.streamToBytes(in);            
+            byte[] dec = Base64.decodeBase64(enc);
+            boolean result = Arrays.equals(buf, dec);
+            if (!result) {
+                System.out.println();
+                System.out.println("testOrigBase64 Failed on : " + testSize);
+            }
+            assertTrue(result);
+        }
+    }
+
+    @Test
+    public void testBase64() throws Exception {
+        Random random = new Random();
+        for (int i = 0; i < 4567; i++) {
+            byte[] buf = new byte[i];
+            random.nextBytes(buf);
+
+            ByteArrayInputStream in = new ByteArrayInputStream( buf );
+            Base64InputStream base64 = new Base64InputStream(in,true);
+            byte[] enc = Util.streamToBytes(base64);
+            in = new ByteArrayInputStream( enc );
+            base64 = new Base64InputStream(in);
+            byte[] dec = Util.streamToBytes(base64);
+
+            boolean result = Arrays.equals(buf, dec);
+            if (!result) {
+                System.out.println();
+                System.out.println("testBase64 Failed on : " + i);                                
+            }
+            assertTrue(result);
+        }
+        for (int i = 5; i < 50; i++) {
+            int testSize = (i * 1000) + 123;
+            byte[] buf = new byte[testSize];
+            random.nextBytes(buf);
+
+            ByteArrayInputStream in = new ByteArrayInputStream( buf );
+            Base64InputStream base64 = new Base64InputStream(in,true);
+            byte[] enc = Util.streamToBytes(base64);
+            in = new ByteArrayInputStream( enc );
+            base64 = new Base64InputStream(in);
+            byte[] dec = Util.streamToBytes(base64);
+
+            boolean result = Arrays.equals(buf, dec);
+            if (!result) {
+                System.out.println();
+                System.out.println("testBase64 Failed on : " + testSize);
+            }
+            assertTrue(result);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestCertificates.java
----------------------------------------------------------------------
diff --git a/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestCertificates.java b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestCertificates.java
new file mode 100644
index 0000000..cc90191
--- /dev/null
+++ b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestCertificates.java
@@ -0,0 +1,87 @@
+package org.apache.commons.ssl;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import javax.security.auth.x500.X500Principal;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import static org.apache.commons.ssl.JUnitConfig.TEST_HOME;
+import static org.mockito.Mockito.when;
+
+/**
+ * Created by julius on 06/09/14.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class TestCertificates {
+
+    @Mock
+    private X509Certificate x509;
+
+    @Test
+    public void testGetCNsMocked() {
+        X500Principal normal = new X500Principal("CN=abc,OU=ou,O=o,C=canada,EMAILADDRESS=bob@bob.com");
+        X500Principal bad1 = new X500Principal("CN=\"abc,CN=foo.com,\",OU=ou,O=o,C=canada,EMAILADDRESS=bob@bob.com");
+        X500Principal bad2 = new X500Principal("ou=\",CN=evil.ca,\",  CN=good.net");
+
+        when(x509.getSubjectX500Principal()).thenReturn(normal);
+        String[] cns = Certificates.getCNs(x509);
+        Assert.assertEquals(1, cns.length);
+        Assert.assertEquals("abc", cns[0]);
+
+        when(x509.getSubjectX500Principal()).thenReturn(bad2);
+        cns = Certificates.getCNs(x509);
+        Assert.assertEquals(1, cns.length);
+        Assert.assertEquals("good.net", cns[0]);
+
+        when(x509.getSubjectX500Principal()).thenReturn(bad1);
+        cns = Certificates.getCNs(x509);
+        Assert.assertEquals(1, cns.length);
+        Assert.assertEquals("abc,CN=foo.com,", cns[0]);
+    }
+
+    @Test
+    public void testGetCNsReal() throws IOException, GeneralSecurityException {
+        String samplesDir = TEST_HOME + "samples/x509";
+
+        TrustMaterial tm = new TrustMaterial(samplesDir + "/x509_three_cns_foo_bar_hanako.pem");
+        X509Certificate c = (X509Certificate) tm.getCertificates().first();
+        String[] cns = Certificates.getCNs(c);
+        Assert.assertEquals(3, cns.length);
+        Assert.assertEquals("foo.com", cns[0]);
+        Assert.assertEquals("bar.com", cns[1]);
+        Assert.assertEquals("花子.co.jp", cns[2]);
+
+        tm = new TrustMaterial(samplesDir + "/x509_foo_bar_hanako.pem");
+        c = (X509Certificate) tm.getCertificates().first();
+        cns = Certificates.getCNs(c);
+        Assert.assertEquals(1, cns.length);
+        Assert.assertEquals("foo.com", cns[0]);
+
+        tm = new TrustMaterial(samplesDir + "/x509_wild_co_jp.pem");
+        c = (X509Certificate) tm.getCertificates().first();
+        cns = Certificates.getCNs(c);
+        Assert.assertEquals(1, cns.length);
+        Assert.assertEquals("*.co.jp", cns[0]);
+
+        tm = new TrustMaterial(samplesDir + "/x509_wild_foo_bar_hanako.pem");
+        c = (X509Certificate) tm.getCertificates().first();
+        cns = Certificates.getCNs(c);
+        Assert.assertEquals(1, cns.length);
+        Assert.assertEquals("*.foo.com", cns[0]);
+
+        tm = new TrustMaterial(samplesDir + "/x509_wild_foo.pem");
+        c = (X509Certificate) tm.getCertificates().first();
+        cns = Certificates.getCNs(c);
+        Assert.assertEquals(1, cns.length);
+        Assert.assertEquals("*.foo.com", cns[0]);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestIPAddressParser.java
----------------------------------------------------------------------
diff --git a/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestIPAddressParser.java b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestIPAddressParser.java
new file mode 100644
index 0000000..4c3cfa0
--- /dev/null
+++ b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestIPAddressParser.java
@@ -0,0 +1,77 @@
+package org.apache.commons.ssl;
+
+import static org.apache.commons.ssl.util.IPAddressParser.*;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+public class TestIPAddressParser {
+
+    @Test
+    public void theTest() {
+
+        // bad ones
+        assertNull("ip6 invalid", parseIPv6Literal(":::"));
+        assertNull("ip6 too many zero-expanders", parseIPv6Literal("1::1::"));
+        assertNull("ip6 .256 invalid", parseIPv6Literal("1::1:255.254.253.256"));
+        assertNull("ip6 too small", parseIPv6Literal("1:2:3:4"));
+        assertNull("ip6 no zero-expander after ip4", parseIPv6Literal("1:255.254.253.252::"));
+        assertNull("ip6 no zero-expander if 7 colons (end)", parseIPv6Literal("1:2:3:4:5:6:7:8::"));
+        assertNull("ip6 no zero-expander if 7 colons (begin)", parseIPv6Literal("::1:2:3:4:5:6:7:8"));
+        assertNull("ip6 88888 too many digits", parseIPv6Literal("1:2:3:4:5:6:7:88888"));
+        assertNull("ip6 missing colons", parseIPv6Literal("abcd"));
+        assertNull("ip6 umm, no", parseIPv6Literal("cookie monster"));
+        assertNull("ip6 empty string is invalid", parseIPv6Literal(""));
+        assertNull("ip6 null is invalid", parseIPv6Literal(null));
+
+        assertNull("ip4 not enough dots", parseIPv4Literal("abcd"));
+        assertNull("ip4 umm, no", parseIPv4Literal("cookie monster"));
+        assertNull("ip4 empty string is invalid", parseIPv4Literal(""));
+        assertNull("ip4 null is invalid", parseIPv4Literal(null));
+        assertNull("ip4 not enough dots 0", parseIPv4Literal("1"));
+        assertNull("ip4 not enough dots 1", parseIPv4Literal("1.2"));
+        assertNull("ip4 not enough dots 2", parseIPv4Literal("1.2.3"));
+        assertNull("ip4 needs digit after final dot", parseIPv4Literal("1.2.3."));
+        assertNull("ip4 [0-9] digits only", parseIPv4Literal("1.2.3.a"));
+        assertNull("ip4 too many dots", parseIPv4Literal("1.2.3.4.5"));
+        assertNull("ip4 0-255 range", parseIPv4Literal("1.2.3.444"));
+        assertNull("ip4 no negatives", parseIPv4Literal("1.2.-3.4"));
+        assertNull("ip4 no brackets", parseIPv4Literal("[1.2.3.4]"));
+
+        // good ones
+        assertArrayEquals(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, parseIPv6Literal("::"));
+        assertArrayEquals(new byte[]{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, parseIPv6Literal("1::"));
+        assertArrayEquals(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, parseIPv6Literal("::1"));
+        assertArrayEquals(new byte[]{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, parseIPv6Literal("1::1"));
+        assertArrayEquals(new byte[]{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, parseIPv6Literal("100::1"));
+
+        assertArrayEquals(new byte[]{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, -3, -4},
+                parseIPv6Literal("1::1:255.254.253.252"));
+
+        assertArrayEquals(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -2, -3, -4},
+                parseIPv6Literal("::255.254.253.252"));
+
+        assertArrayEquals(new byte[]{0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, -1, -2, -3, -4},
+                parseIPv6Literal("1:2:3:4:5:6:255.254.253.252"));
+
+        assertArrayEquals(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4}, parseIPv6Literal("::1:2:3:4"));
+        assertArrayEquals(new byte[]{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4}, parseIPv6Literal("1::2:3:4"));
+        assertArrayEquals(new byte[]{0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 4}, parseIPv6Literal("1:2::3:4"));
+        assertArrayEquals(new byte[]{0, 1, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}, parseIPv6Literal("1:2:3::4"));
+        assertArrayEquals(new byte[]{0, 1, 0, 2, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, parseIPv6Literal("1:2:3:4::"));
+
+        assertArrayEquals(new byte[]{0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8},
+                parseIPv6Literal("1:2:3:4:5:6:7:8"));
+
+        assertArrayEquals(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, parseIPv6Literal("[::]"));
+
+        assertArrayEquals(new byte[]{0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8},
+                parseIPv6Literal("[1:2:3:4:5:6:7:8]"));
+
+        assertArrayEquals(new byte[]{17, 17, 34, 34, 51, 51, 68, 68, 85, 85, 102, 102, 119, 119, -120, -120},
+                parseIPv6Literal("1111:2222:3333:4444:5555:6666:7777:8888"));
+
+        assertArrayEquals(new byte[]{0, 0, 0, 0}, parseIPv4Literal("0.0.0.0"));
+        assertArrayEquals(new byte[]{1, 2, 3, 4}, parseIPv4Literal("1.2.3.4"));
+        assertArrayEquals(new byte[]{-1, -1, -1, -1}, parseIPv4Literal("255.255.255.255"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestKeyMaterial.java
----------------------------------------------------------------------
diff --git a/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestKeyMaterial.java b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestKeyMaterial.java
new file mode 100644
index 0000000..01932ec
--- /dev/null
+++ b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestKeyMaterial.java
@@ -0,0 +1,118 @@
+package org.apache.commons.ssl;
+
+import static org.apache.commons.ssl.JUnitConfig.TEST_HOME;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import javax.net.ssl.SSLSocket;
+
+public class TestKeyMaterial {
+    public static final char[] PASSWORD1 = "changeit".toCharArray();
+    public static final char[] PASSWORD2 = "itchange".toCharArray();
+
+    static {
+        Security.addProvider(new BouncyCastleProvider());
+    }
+
+    @Test
+    public void testKeystores() throws Exception {
+        String samplesDir = TEST_HOME + "samples/keystores";
+        File dir = new File(samplesDir);
+        String[] files = dir.list();
+        Arrays.sort(files, String.CASE_INSENSITIVE_ORDER);
+        for (String f : files) {
+            String F = f.toUpperCase(Locale.ENGLISH);
+            if (F.endsWith(".KS") || F.contains("PKCS12")) {
+                examineKeyStore(samplesDir, f, null);
+            } else if (F.endsWith(".PEM")) {
+                examineKeyStore(samplesDir, f, "rsa.key");
+            }
+        }
+    }
+
+    private static void examineKeyStore(String dir, String fileName, String file2) throws Exception {
+        String FILENAME = fileName.toUpperCase(Locale.ENGLISH);
+        boolean hasMultiPassword = FILENAME.contains(".2PASS.");
+
+        System.out.print("Testing KeyMaterial: " + dir + "/" + fileName);        
+        char[] pass1 = PASSWORD1;
+        char[] pass2 = PASSWORD1;
+        if (hasMultiPassword) {
+            pass2 = PASSWORD2;
+        }
+
+        file2 = file2 != null ? dir + "/" + file2 : null;
+
+        Date today = new Date();
+        KeyMaterial km;
+        try {
+            km = new KeyMaterial(dir + "/" + fileName, file2, pass1, pass2);
+        } catch (ProbablyBadPasswordException pbpe) {
+            System.out.println("  WARN:  " + pbpe);
+            return;
+        }
+        assertEquals("keymaterial-contains-1-alias", 1, km.getAliases().size());
+        for (X509Certificate[] cert : (List<X509Certificate[]>) km.getAssociatedCertificateChains()) {
+            for (X509Certificate c : cert) {
+                assertTrue("certchain-valid-dates", c.getNotAfter().after(today));
+            }
+        }
+
+        SSLServer server = new SSLServer();
+        server.setKeyMaterial(km);
+        ServerSocket ss = server.createServerSocket(0);
+        int port = ss.getLocalPort();
+        startServerThread(ss);
+        Thread.sleep(1);
+
+
+        SSLClient client = new SSLClient();
+        client.setTrustMaterial(TrustMaterial.TRUST_ALL);
+        client.setCheckHostname(false);
+        SSLSocket s = (SSLSocket) client.createSocket("localhost", port);
+        s.getSession().getPeerCertificates();
+        InputStream in = s.getInputStream();
+        Util.streamToBytes(in);
+        in.close();
+        // System.out.println(Certificates.toString((X509Certificate) certs[0]));
+        s.close();
+
+        System.out.println("\t SUCCESS! ");
+    }
+
+
+    private static void startServerThread(final ServerSocket ss) {
+        Runnable r = new Runnable() {
+            public void run() {
+                try {
+                    Socket s = ss.accept();
+                    OutputStream out = s.getOutputStream();
+                    Thread.sleep(1);
+                    out.write("Hello From Server\n".getBytes());
+                    Thread.sleep(1);
+                    out.close();
+                    s.close();
+                } catch (Exception e) {
+
+                    System.out.println("Test ssl server exception: " + e);
+
+                }
+            }
+        };
+
+        new Thread(r).start();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestOpenSSL.java
----------------------------------------------------------------------
diff --git a/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestOpenSSL.java b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestOpenSSL.java
new file mode 100644
index 0000000..d44a260
--- /dev/null
+++ b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestOpenSSL.java
@@ -0,0 +1,150 @@
+package org.apache.commons.ssl;
+
+import static org.apache.commons.ssl.JUnitConfig.TEST_HOME;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Random;
+
+public class TestOpenSSL {
+
+    public void encTest(String cipher) throws Exception {
+        Random random = new Random();
+        char[] pwd = {'!', 'E', 'i', 'k', 'o', '?'};
+
+        for (int i = 0; i < 4567; i++) {
+            byte[] buf = new byte[i];
+            random.nextBytes(buf);
+            byte[] enc = OpenSSL.encrypt(cipher, pwd, buf);
+            byte[] dec = OpenSSL.decrypt(cipher, pwd, enc);
+            boolean result = Arrays.equals(buf, dec);
+            if (!result) {
+                System.out.println();
+                System.out.println("Failed on : " + i);
+            }
+            assertTrue(result);
+        }
+
+        for (int i = 5; i < 50; i++) {
+            int testSize = (i * 1000) + 123;
+            byte[] buf = new byte[testSize];
+            random.nextBytes(buf);
+            byte[] enc = OpenSSL.encrypt(cipher, pwd, buf);
+            byte[] dec = OpenSSL.decrypt(cipher, pwd, enc);
+            boolean result = Arrays.equals(buf, dec);
+            if (!result) {
+                System.out.println();
+                System.out.println("Failed on : " + testSize);
+            }
+            assertTrue(result);
+        }
+
+    }
+
+    @Test
+    public void testDES3Bytes() throws Exception {
+        encTest("des3");
+    }
+
+    @Test
+    public void testAES128Bytes() throws Exception {
+        encTest("aes128");
+    }
+
+    @Test
+    public void testRC2Bytes() throws Exception {
+        encTest("rc2");
+    }
+
+    @Test
+    public void testDESBytes() throws Exception {
+        encTest("des");
+    }
+
+    @Test
+    public void testDecryptPBE() throws Exception {
+        File d = new File(TEST_HOME + "samples/pbe");
+        File[] files = d.listFiles();
+        if (files == null) {
+            fail("No testDecryptPBE() files to test!");
+        }
+        int testCount = 0;
+        Arrays.sort(files);
+        for (File f : files) {
+            testCount += process(f, 0);
+        }
+        System.out.println(testCount + " pbe test files successfully decrypted.");
+    }
+
+    private static int process(File f, int depth) throws Exception {
+        int sum = 0;
+        String name = f.getName();
+        if ("CVS".equalsIgnoreCase(name)) {
+            return 0;
+        }
+        if (".svn".equalsIgnoreCase(name)) {
+            return 0;
+        }
+        if (name.toUpperCase().startsWith("README")) {
+            return 0;
+        }
+
+        if (f.isDirectory()) {
+            if (depth <= 7) {
+                File[] files = f.listFiles();
+                if (files == null) {
+                    return 0;
+                }
+                Arrays.sort(files);
+                for (File ff : files) {
+                    sum += process(ff, depth + 1);
+                }
+            } else {
+                System.out.println("IGNORING [" + f + "].  Directory too deep (" + depth + ").");
+            }
+        } else {
+            if (f.isFile() && f.canRead()) {
+                String fileName = f.getName();
+                int x = fileName.indexOf('.');
+                if (x < 0) {
+                    return 0;
+                }
+                String cipher = fileName.substring(0, x);
+                String cipherPadded = Util.pad(cipher, 20, false);
+                String filePadded = Util.pad(fileName, 25, false);
+                FileInputStream in = null;
+                try {
+                    in = new FileInputStream(f);
+                    byte[] encrypted = Util.streamToBytes(in);
+                    char[] pwd = "changeit".toCharArray();
+                    try {
+                        byte[] result = OpenSSL.decrypt(cipher, pwd, encrypted);
+                        String s = new String(result, "ISO-8859-1");
+                        assertTrue(cipherPadded + "." + filePadded + " decrypts to 'Hello World!'", "Hello World!".equals(s));
+                        return 1;
+                    } catch (NoSuchAlgorithmException nsae) {
+                        System.out.println("Warn: " + cipherPadded + filePadded + " NoSuchAlgorithmException");
+                        return 0;
+                    } catch (ArithmeticException ae) {
+                        if (cipherPadded.contains("cfb1")) {
+                            System.out.println("Warn: " + cipherPadded + filePadded + " BouncyCastle can't handle cfb1 " + ae);
+                            return 0;
+                        } else {
+                            throw ae;
+                        }
+                    }
+                } finally {
+                    if (in != null) {
+                        in.close();
+                    }
+                }
+            }
+        }
+        return sum;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestPKCS8Key.java
----------------------------------------------------------------------
diff --git a/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestPKCS8Key.java b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestPKCS8Key.java
new file mode 100644
index 0000000..31da307
--- /dev/null
+++ b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestPKCS8Key.java
@@ -0,0 +1,54 @@
+package org.apache.commons.ssl;
+
+import static org.apache.commons.ssl.JUnitConfig.TEST_HOME;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Arrays;
+import java.util.Locale;
+
+public class TestPKCS8Key {
+
+    @Test
+    public void testDSA() throws Exception {
+        checkFiles("dsa");
+    }
+
+    @Test
+    public void testRSA() throws Exception {
+        checkFiles("rsa");
+    }
+
+    private static void checkFiles(String type) throws Exception {
+        String password = "changeit";
+        File dir = new File(TEST_HOME + "samples/" + type);
+        File[] files = dir.listFiles();
+        if (files == null) {
+            fail("No files to test!");
+            return;
+        }
+        byte[] original = null;
+        for (File f : files) {
+            String filename = f.getName();
+            String FILENAME = filename.toUpperCase(Locale.ENGLISH);
+            if (!FILENAME.endsWith(".PEM") && !FILENAME.endsWith(".DER")) {
+                // not a sample file
+                continue;
+            }
+
+            FileInputStream in = new FileInputStream(f);
+            byte[] bytes = Util.streamToBytes(in);
+            PKCS8Key key = new PKCS8Key(bytes, password.toCharArray());
+            byte[] decrypted = key.getDecryptedBytes();
+            if (original == null) {
+                original = decrypted;
+            } else {
+                boolean identical = Arrays.equals(original, decrypted);
+                assertTrue(f.getCanonicalPath() + " - all " + type + " samples decrypt to same key", identical);
+            }
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestTrustMaterial.java
----------------------------------------------------------------------
diff --git a/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestTrustMaterial.java b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestTrustMaterial.java
new file mode 100644
index 0000000..ddbfbfe
--- /dev/null
+++ b/3rdparty/not-yet-commons-ssl/src/test/java/org/apache/commons/ssl/TestTrustMaterial.java
@@ -0,0 +1,65 @@
+package org.apache.commons.ssl;
+
+import static org.apache.commons.ssl.JUnitConfig.TEST_HOME;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStoreException;
+
+public class TestTrustMaterial {
+
+    File pemFile = new File(TEST_HOME + "samples/x509/certificate.pem");
+    File derFile = new File(TEST_HOME + "samples/x509/certificate.der");
+
+    @Test
+    public void theTest() throws GeneralSecurityException, IOException {
+        // TrustMaterial in 0.3.13 couldn't load cacerts if it contained any private keys.
+        TrustMaterial tm = new TrustMaterial(TEST_HOME + "samples/cacerts-with-78-entries-and-one-private-key.jks");
+        Assert.assertEquals(78, tm.getCertificates().size());
+    }
+
+    @Test
+    public void testLoadByFile() throws GeneralSecurityException, IOException {
+        TrustMaterial tm1 = new TrustMaterial(pemFile);
+        TrustMaterial tm2 = new TrustMaterial(derFile);
+        Assert.assertTrue(equalKeystores(tm1, tm2));
+    }
+
+    @Test
+    public void testLoadByBytes() throws GeneralSecurityException, IOException {
+        TrustMaterial tm1 = new TrustMaterial(Util.fileToBytes(pemFile));
+        TrustMaterial tm2 = new TrustMaterial(Util.fileToBytes(derFile));
+        Assert.assertTrue(equalKeystores(tm1, tm2));
+
+    }
+
+    @Test
+    public void testLoadByURL() throws GeneralSecurityException, IOException {
+        TrustMaterial tm1 = new TrustMaterial(pemFile.toURI().toURL());
+        TrustMaterial tm2 = new TrustMaterial(derFile.toURI().toURL());
+        Assert.assertTrue(equalKeystores(tm1, tm2));
+    }
+
+    @Test
+    public void testLoadByStream() throws GeneralSecurityException, IOException {
+        TrustMaterial tm1 = new TrustMaterial(new FileInputStream(pemFile));
+        TrustMaterial tm2 = new TrustMaterial(new FileInputStream(derFile));
+        Assert.assertTrue(equalKeystores(tm1, tm2));
+
+    }
+
+    @Test
+    public void testLoadByPath() throws GeneralSecurityException, IOException {
+        TrustMaterial tm1 = new TrustMaterial(pemFile.getPath());
+        TrustMaterial tm2 = new TrustMaterial(derFile.getPath());
+        Assert.assertTrue(equalKeystores(tm1, tm2));
+    }
+
+    private static boolean equalKeystores(TrustMaterial tm1, TrustMaterial tm2) throws KeyStoreException {
+        return Util.equals(tm1.getKeyStore(), tm2.getKeyStore());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/not-yet-commons-ssl/version.txt
----------------------------------------------------------------------
diff --git a/3rdparty/not-yet-commons-ssl/version.txt b/3rdparty/not-yet-commons-ssl/version.txt
new file mode 100644
index 0000000..d8913dd
--- /dev/null
+++ b/3rdparty/not-yet-commons-ssl/version.txt
@@ -0,0 +1 @@
+$URL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.16/version.txt $

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/3rdparty/pom.xml
----------------------------------------------------------------------
diff --git a/3rdparty/pom.xml b/3rdparty/pom.xml
new file mode 100644
index 0000000..b8a816c
--- /dev/null
+++ b/3rdparty/pom.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.haox</groupId>
+        <artifactId>haox-all</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>3rdparty</artifactId>
+    <name>Third Party Projects</name>
+    <description>Third Party Projects</description>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>not-yet-commons-ssl</module>
+    </modules>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.8.2</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ad410e1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0c53256
--- /dev/null
+++ b/README.md
@@ -0,0 +1,97 @@
+Haox
+====
+
+Haox aims for a Java Kerberos binding, and provides richful, inituitive and interoperable implementation, library and various facilities that integrate Kerberos, PKI and token (OAuth) as desired in modern environments such as mobile, cloud and Hadoop. 
+
+### The Initiatives/Goals 
+* Aims as a Java Kerberos binding, with richful and integrated facilities that integrate Kerberos, PKI and token (OAuth) for both client and server sides.
++ Provides client APIs in Kerberos protocol level to interact with a KDC server thru AS and TGS exchanges.
++ Provides an embeded KDC server that applications can easily integrate into products, unit tests or integration tests.
++ Supports FAST/Preauthentication framework to allow popular and useful authentication mechanisms.
++ Supports PKINIT mechanism to allow clients to request tickets using x509 certificate credential.
++ Supports Token Preauth mechanism to allow clients to request tickets using JWT tokens.
++ Provides support for JAAS, GSSAPI and SASL frameworks that applications can leverage.
++ Least dependency, the core part is ensured to depend only on JRE, for easy use and maintain.
+
+### Update
+We’re collaborating with ApacheDS community and preparing this project to be ready for a sub project. Feedback is welcome.
+
+### Status
+As follows, with the core and critical parts done, important features are still ongoing.
+It's going to release 0.1 version in the early next year. We do not suggest production usage prior to the release.
+<pre>
+ASN-1 (done)
+Kerberos core and codec (done)
+Kerberos Crypto (done)
+Embedded KDC (the core done)
+KrbClient (partial APIs done and available)
+Preauth/FAST framework (partially done)
+Token Preauth (ongoing)
+PKINIT (ongoing)
+Keytab util (credential cache and keytab support, done)
+</pre>
+
+### Desired KrbClient APIs (partialy done)
+* Initiate a KrbClient
+<pre>
+KrbClient krbClient = new KrbClient(kdcHost, kdcPort);
+</pre>
+* Request a TGT with user plain password credential
+<pre>
+krbClient.requestTgtTicket(principal, password);
+</pre>
+* Request a TGT with user x509 certificate credential
+<pre>
+krbClient.requestTgtTicket(principal, certificate);
+</pre>
+* Request a TGT with user token credential
+<pre>
+krbClient.requestTgtTicket(principal, kerbToken);
+</pre>
+* Request a service ticket with user TGT credential for a server
+<pre>
+krbClient.requestServiceTicket(tgt, serverPrincipal);
+</pre>
+* Request a service ticket with user AccessToken credential for a server
+<pre>
+krbClient.requestServiceTicket(accessToken, serverPrincipal);
+</pre>
+
+### The ASN-1 support
+Please look at [haox-asn1](https://github.com/drankye/haox/blob/master/haox-asn1/README.md) for details.
+
+### Kerberos Crypto and Encryption Types
+Implementing des, des3, rc4, aes, camellia encryption and corresponding checksum types
+Interoperates with MIT Kerberos and Microsoft AD
+Independent with Kerberos codes in JRE, but rely on JCE
+
+| Encryption Type | Description |
+| --------------- | ----------- |
+| des-cbc-crc | DES cbc mode with CRC-32 (weak) |
+| des-cbc-md4 | DES cbc mode with RSA-MD4 (weak) |
+| des-cbc-md5 |	DES cbc mode with RSA-MD5 (weak) |
+| des3-cbc-sha1 des3-hmac-sha1 des3-cbc-sha1-kd |	Triple DES cbc mode with HMAC/sha1 |
+| des-hmac-sha1 |	DES with HMAC/sha1 (weak) |
+| aes256-cts-hmac-sha1-96 aes256-cts AES-256 	| CTS mode with 96-bit SHA-1 HMAC |
+| aes128-cts-hmac-sha1-96 aes128-cts AES-128 	| CTS mode with 96-bit SHA-1 HMAC |
+| arcfour-hmac rc4-hmac arcfour-hmac-md5 |	RC4 with HMAC/MD5 |
+| arcfour-hmac-exp rc4-hmac-exp arcfour-hmac-md5-exp |	Exportable RC4 with HMAC/MD5 (weak) |
+| camellia256-cts-cmac camellia256-cts |	Camellia-256 CTS mode with CMAC |
+| camellia128-cts-cmac camellia128-cts |	Camellia-128 CTS mode with CMAC |
+| des |	The DES family: des-cbc-crc, des-cbc-md5, and des-cbc-md4 (weak) |
+| des3 |	The triple DES family: des3-cbc-sha1 |
+| aes |	The AES family: aes256-cts-hmac-sha1-96 and aes128-cts-hmac-sha1-96 |
+| rc4 |	The RC4 family: arcfour-hmac |
+| camellia | The Camellia family: camellia256-cts-cmac and camellia128-cts-cmac |
+
+### Dependency
+The core part is ensured to only depend on JRE. Every external dependency is taken carefully and maintained separately.
+
+##### Contrib Projects
+- haox-asn1. A model driven ASN-1 encoding and decoding framework
+- haox-event. A pure event driven application framework aiming to construct applications of asynchronous and concurrent handlers. It includes UDP and TCP transport based on pure Java NIO and concurrency pattern.
+- haox-config. A unified configuration API that aims to support various configuration file formats, like XML, JNI, CSV and Java Properties file.
+- haox-token. Implements a JWT token API for Kerberos that's defined in TokenPreauth drafts.
+
+### License
+Apache License V2.0

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/benchmark/pom.xml
----------------------------------------------------------------------
diff --git a/benchmark/pom.xml b/benchmark/pom.xml
new file mode 100644
index 0000000..7b1733a
--- /dev/null
+++ b/benchmark/pom.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>haox-all</artifactId>
+        <groupId>org.haox</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>benchmark</artifactId>
+
+    <name>Haox benchmark</name>
+    <description>Haox benchmark tests</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.haox</groupId>
+            <artifactId>haox-asn1</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.haox</groupId>
+            <artifactId>kerb-core</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.haox</groupId>
+            <artifactId>kerb-util</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.server</groupId>
+            <artifactId>apacheds-core-api</artifactId>
+            <version>2.0.0-M15</version>
+            <scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.directory.api</groupId>
+                    <artifactId>api-ldap-schema-data</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.server</groupId>
+            <artifactId>apacheds-interceptor-kerberos</artifactId>
+            <version>2.0.0-M15</version>
+            <scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.directory.api</groupId>
+                    <artifactId>api-ldap-schema-data</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.server</groupId>
+            <artifactId>apacheds-protocol-shared</artifactId>
+            <version>2.0.0-M15</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.server</groupId>
+            <artifactId>apacheds-protocol-kerberos</artifactId>
+            <version>2.0.0-M15</version>
+            <scope>compile</scope>
+            <exclusions>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.server</groupId>
+            <artifactId>apacheds-ldif-partition</artifactId>
+            <version>2.0.0-M15</version>
+            <scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.directory.api</groupId>
+                    <artifactId>api-ldap-schema-data</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.server</groupId>
+            <artifactId>apacheds-mavibot-partition</artifactId>
+            <version>2.0.0-M15</version>
+            <scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.directory.api</groupId>
+                    <artifactId>api-ldap-schema-data</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-all</artifactId>
+            <version>1.0.0-M20</version>
+            <scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>xml-apis</groupId>
+                    <artifactId>xml-apis</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>xpp3</groupId>
+                    <artifactId>xpp3</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>dom4j</groupId>
+                    <artifactId>dom4j</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/benchmark/src/main/resources/apreq.token
----------------------------------------------------------------------
diff --git a/benchmark/src/main/resources/apreq.token b/benchmark/src/main/resources/apreq.token
new file mode 100644
index 0000000..c02318a
Binary files /dev/null and b/benchmark/src/main/resources/apreq.token differ

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/benchmark/src/test/java/org/apache/kerberos/benchmark/KrbCodecPerfTest.java
----------------------------------------------------------------------
diff --git a/benchmark/src/test/java/org/apache/kerberos/benchmark/KrbCodecPerfTest.java b/benchmark/src/test/java/org/apache/kerberos/benchmark/KrbCodecPerfTest.java
new file mode 100644
index 0000000..254c226
--- /dev/null
+++ b/benchmark/src/test/java/org/apache/kerberos/benchmark/KrbCodecPerfTest.java
@@ -0,0 +1,60 @@
+package org.apache.kerberos.benchmark;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.kerberos.codec.apReq.ApReqContainer;
+import org.apache.kerberos.kerb.KrbException;
+import org.apache.kerberos.kerb.spec.ap.ApReq;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+public class KrbCodecPerfTest {
+
+    public static void main(String[] args) throws KrbException, IOException, DecoderException, EncoderException {
+        InputStream is = KrbCodecPerfTest.class.getResourceAsStream("/apreq.token");
+        byte[] bytes = new byte[is.available()];
+        is.read(bytes);
+
+        int times = 1000000;
+        perfApacheDS(ByteBuffer.wrap(bytes), times);
+        perfHaox(ByteBuffer.wrap(bytes), times);
+    }
+
+    private static void perfHaox(ByteBuffer apreqToken, int times) throws KrbException, IOException {
+        long start = System.currentTimeMillis();
+
+        for (int i = 0; i < times; ++i) {
+            //ApReq apReq = KrbCodec.decode(apreqToken, ApReq.class);
+            ApReq apReq = new ApReq(); apReq.decode(apreqToken);
+            if (apReq == null) {
+                throw new RuntimeException("Decoding failed");
+            }
+            String serverName = apReq.getTicket().getSname().toString();
+
+            apreqToken.rewind();
+        }
+
+        long end = System.currentTimeMillis();
+        System.out.println("HaoxCodec takes:" + (end - start));
+    }
+
+    private static void perfApacheDS(ByteBuffer apreqToken, int times) throws EncoderException, DecoderException {
+        long start = System.currentTimeMillis();
+
+        for (int i = 0; i < times; ++i) {
+            Asn1Decoder krbDecoder = new Asn1Decoder();
+            ApReqContainer apreqContainer = new ApReqContainer(apreqToken);
+            krbDecoder.decode(apreqToken, apreqContainer);
+            String serverName = apreqContainer.getApReq().getTicket().getSName().toString();
+
+            apreqToken.rewind();
+        }
+
+        long end = System.currentTimeMillis();
+        System.out.println("ApacheDS takes:" + (end - start));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/README.md
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/README.md b/contrib/haox-asn1/README.md
new file mode 100644
index 0000000..b8b3492
--- /dev/null
+++ b/contrib/haox-asn1/README.md
@@ -0,0 +1,284 @@
+haox-asn1
+=========
+
+### A ASN1 parser with easy and simple API
+
+```
+// encoding
+Asn1Integer aValue = new Asn1Integer(8899);
+byte[] encoded = aValue.encode();
+
+// decoding
+byte[] contentToDecode = ...
+Asn1Integer decodedValue = new Asn1Integer();
+decodedValue.decode(contentToDecode);
+Integer value = decodedValue.getValue();
+```
+
+### Data-driven ASN1 encoding/decoding framework and parser
+
+With the following definition from Kerberos protocol
+```
+ AuthorizationData ::= SEQUENCE OF SEQUENCE {
+     ad-type         [0] Int32,
+     ad-data         [1] OCTET STRING
+ }
+ ```
+ 
+You can model AuthzDataEntry as follows
+```java
+public class AuthzDataEntry extends Asn1SequenceType {
+    static int AD_TYPE = 0;
+    static int AD_DATA = 1;
+
+    public AuthzDataEntry() {
+        super(new Asn1FieldInfo[] {
+                new Asn1FieldInfo(AD_TYPE, Asn1Integer.class),
+                new Asn1FieldInfo(AD_DATA, Asn1OctetString.class)
+        });
+    }
+
+    public int getAuthzType() {
+        Integer value = getFieldAsInteger(AD_TYPE);
+        return value;
+    }
+
+    public byte[] getAuthzData() {
+        return getFieldAsOctetBytes(AD_DATA);
+    }
+}
+```
+
+And then define AuthorizationData simply
+```java
+public class AuthorizationData extends Asn1SequenceOf<AuthzDataEntry> {
+
+}
+```
+
+Then you can process with above definitions, encode and decode, without caring about the details.
+
+Think about how to implement the following more complex and pratical sample from [ITU-T Rec. X.680 ISO/IEC 8824-1](http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf):
+```
+A.1 ASN.1 description of the record structure
+The structure of the hypothetical personnel record is formally described below using ASN.1 specified in
+ITU-T Rec. X.680 | ISO/IEC 8824-1 for defining types.
+
+PersonnelRecord ::= [APPLICATION 0] IMPLICIT SET {
+    Name Name,
+    title [0] VisibleString,
+    number EmployeeNumber,
+    dateOfHire [1] Date,
+    nameOfSpouse [2] Name,
+    children [3] IMPLICIT
+    SEQUENCE OF ChildInformation DEFAULT {} 
+}
+
+ChildInformation ::= SET {
+    name Name,
+    dateOfBirth [0] Date
+}
+
+Name ::= [APPLICATION 1] IMPLICIT SEQUENCE {
+    givenName VisibleString,
+    initial VisibleString,
+    familyName VisibleString
+}
+
+EmployeeNumber ::= [APPLICATION 2] IMPLICIT INTEGER
+Date ::= [APPLICATION 3] IMPLICIT VisibleString -- YYYYMMDD
+```
+Similarly as above, we can have (from the unit test codes):
+```java
+public class PersonnelRecord extends TaggingSet {
+    private static int NAME = 0;
+    private static int TITLE = 1;
+    private static int NUMBER = 2;
+    private static int DATEOFHIRE= 3;
+    private static int NAMEOFSPOUSE = 4;
+    private static int CHILDREN = 5;
+
+    static Asn1FieldInfo[] fieldInfos = new Asn1FieldInfo[] {
+            new Asn1FieldInfo(NAME, -1, Name.class),
+            new Asn1FieldInfo(TITLE, 0, Asn1VisibleString.class),
+            new Asn1FieldInfo(NUMBER, -1, EmployeeNumber.class),
+            new Asn1FieldInfo(DATEOFHIRE, 1, Date.class),
+            new Asn1FieldInfo(NAMEOFSPOUSE, 2, Name.class),
+            new Asn1FieldInfo(CHILDREN, 3, Children.class, true)
+    };
+
+    public PersonnelRecord() {
+        super(0, fieldInfos, true);
+        setEncodingOption(EncodingOption.IMPLICIT);
+    }
+
+    public void setName(Name name) {
+        setFieldAs(NAME, name);
+    }
+
+    public Name getName() {
+        return getFieldAs(NAME, Name.class);
+    }
+
+    public void setTitle(String title) {
+        setFieldAs(TITLE, new Asn1VisibleString(title));
+    }
+
+    public String getTitle() {
+        return getFieldAsString(TITLE);
+    }
+
+    public void setEmployeeNumber(EmployeeNumber employeeNumber) {
+        setFieldAs(NUMBER, employeeNumber);
+    }
+
+    public EmployeeNumber getEmployeeNumber() {
+        return getFieldAs(NUMBER, EmployeeNumber.class);
+    }
+
+    public void setDateOfHire(Date dateOfHire) {
+        setFieldAs(DATEOFHIRE, dateOfHire);
+    }
+
+    public Date getDateOfHire() {
+        return getFieldAs(DATEOFHIRE, Date.class);
+    }
+
+    public void setNameOfSpouse(Name spouse) {
+        setFieldAs(NAMEOFSPOUSE, spouse);
+    }
+
+    public Name getNameOfSpouse() {
+        return getFieldAs(NAMEOFSPOUSE, Name.class);
+    }
+
+    public void setChildren(Children children) {
+        setFieldAs(CHILDREN, children);
+    }
+
+    public Children getChildren() {
+        return getFieldAs(CHILDREN, Children.class);
+    }
+
+    public static class Children extends Asn1SequenceOf<ChildInformation> {
+        public Children(ChildInformation ... children) {
+            super();
+            for (ChildInformation child : children) {
+                addElement(child);
+            }
+        }
+
+        public Children() {
+            super();
+        }
+    }
+
+    public static class ChildInformation extends Asn1SetType {
+        private static int NAME = 0;
+        private static int DATEOFBIRTH = 1;
+
+        static Asn1FieldInfo[] tags = new Asn1FieldInfo[] {
+                new Asn1FieldInfo(NAME, -1, Name.class),
+                new Asn1FieldInfo(DATEOFBIRTH, 0, Date.class)
+        };
+
+        public ChildInformation() {
+            super(tags);
+        }
+
+        public void setName(Name name) {
+            setFieldAs(NAME, name);
+        }
+
+        public Name getName() {
+            return getFieldAs(NAME, Name.class);
+        }
+
+        public void setDateOfBirth(Date date) {
+            setFieldAs(DATEOFBIRTH, date);
+        }
+
+        public Date getDateOfBirth() {
+            return getFieldAs(DATEOFBIRTH, Date.class);
+        }
+    }
+
+    public static class Name extends TaggingSequence {
+        private static int GIVENNAME = 0;
+        private static int INITIAL = 1;
+        private static int FAMILYNAME = 2;
+
+        static Asn1FieldInfo[] tags = new Asn1FieldInfo[] {
+                new Asn1FieldInfo(GIVENNAME, -1, Asn1VisibleString.class),
+                new Asn1FieldInfo(INITIAL, -1, Asn1VisibleString.class),
+                new Asn1FieldInfo(FAMILYNAME, -1, Asn1VisibleString.class)
+        };
+
+        public Name() {
+            super(1, tags, true);
+            setEncodingOption(EncodingOption.IMPLICIT);
+        }
+
+        public Name(String givenName, String initial, String familyName) {
+            this();
+            setGivenName(givenName);
+            setInitial(initial);
+            setFamilyName(familyName);
+        }
+
+        public void setGivenName(String givenName) {
+            setFieldAs(GIVENNAME, new Asn1VisibleString(givenName));
+        }
+
+        public String getGivenName() {
+            return getFieldAsString(GIVENNAME);
+        }
+
+        public void setInitial(String initial) {
+            setFieldAs(INITIAL, new Asn1VisibleString(initial));
+        }
+
+        public String getInitial() {
+            return getFieldAsString(INITIAL);
+        }
+
+        public void setFamilyName(String familyName) {
+            setFieldAs(FAMILYNAME, new Asn1VisibleString(familyName));
+        }
+
+        public String getFamilyName() {
+            return getFieldAsString(FAMILYNAME);
+        }
+    }
+
+    public static class EmployeeNumber extends Asn1Tagging<Asn1Integer> {
+        public EmployeeNumber(Integer value) {
+            super(2, new Asn1Integer(value), true);
+            setEncodingOption(EncodingOption.IMPLICIT);
+        }
+        public EmployeeNumber() {
+            this(null);
+        }
+    }
+
+    public static class Date extends Asn1Tagging<Asn1VisibleString> {
+        public Date(String value) {
+            super(3, new Asn1VisibleString(value), true);
+            setEncodingOption(EncodingOption.IMPLICIT);
+        }
+        public Date() {
+            this(null);
+        }
+    }
+}
+```
+### Notes
+* 90% tests coverage for DER encoding
+* For BER & CER encoding, to be fully supported
+* No extra dependency
+
+### License
+Apache V2 License
+
+
+

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/pom.xml b/contrib/haox-asn1/pom.xml
new file mode 100644
index 0000000..b07008d
--- /dev/null
+++ b/contrib/haox-asn1/pom.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>contrib</artifactId>
+        <groupId>org.haox</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>haox-asn1</artifactId>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1Dump.java
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1Dump.java b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1Dump.java
new file mode 100644
index 0000000..2c2d7ed
--- /dev/null
+++ b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1Dump.java
@@ -0,0 +1,51 @@
+package org.apache.haox.asn1;
+
+import org.apache.haox.asn1.type.Asn1Item;
+import org.apache.haox.asn1.type.Asn1Simple;
+import org.apache.haox.asn1.type.Asn1Type;
+
+import java.io.IOException;
+
+public class Asn1Dump {
+
+    public static void dump(byte[] content) throws IOException {
+        String dumped = dumpAsString(content);
+        System.out.println(dumped);
+    }
+
+    public static String dumpAsString(byte[] content) throws IOException {
+        StringBuilder sb = new StringBuilder();
+
+        Asn1InputBuffer buffer = new Asn1InputBuffer(content);
+        Asn1Type value;
+        while (true) {
+            value = buffer.read();
+            if (value == null) break;
+            dump(value, sb);
+        }
+
+        return sb.toString();
+    }
+
+    public static String dumpAsString(Asn1Type value) {
+        StringBuilder sb = new StringBuilder();
+        dump(value, sb);
+        return sb.toString();
+    }
+
+    private static void dump(Asn1Type value, StringBuilder buffer) {
+        if (value instanceof Asn1Simple) {
+            buffer.append(((Asn1Simple) value).getValue().toString());
+        } else if (value instanceof Asn1Item) {
+            dump((Asn1Item) value, buffer);
+        }
+    }
+
+    private static void dump(Asn1Item value, StringBuilder buffer) {
+        if (value.isFullyDecoded()) {
+            dump(value.getValue(), buffer);
+        } else {
+            buffer.append("Asn1Item");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1Factory.java
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1Factory.java b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1Factory.java
new file mode 100644
index 0000000..c35059b
--- /dev/null
+++ b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1Factory.java
@@ -0,0 +1,25 @@
+package org.apache.haox.asn1;
+
+import org.apache.haox.asn1.type.Asn1Collection;
+import org.apache.haox.asn1.type.Asn1Simple;
+import org.apache.haox.asn1.type.Asn1Type;
+
+public class Asn1Factory {
+
+    public static Asn1Type create(int tagNo) {
+        UniversalTag tagNoEnum = UniversalTag.fromValue(tagNo);
+        if (tagNoEnum != UniversalTag.UNKNOWN) {
+            return create(tagNoEnum);
+        }
+        throw new IllegalArgumentException("Unexpected tag " + tagNo);
+    }
+
+    public static Asn1Type create(UniversalTag tagNo) {
+        if (Asn1Simple.isSimple(tagNo)) {
+            return Asn1Simple.createSimple(tagNo);
+        } else if (Asn1Collection.isCollection(tagNo)) {
+            return Asn1Collection.createCollection(tagNo);
+        }
+        throw new IllegalArgumentException("Unexpected tag " + tagNo);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1InputBuffer.java
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1InputBuffer.java b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1InputBuffer.java
new file mode 100644
index 0000000..11045df
--- /dev/null
+++ b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1InputBuffer.java
@@ -0,0 +1,63 @@
+package org.apache.haox.asn1;
+
+import org.apache.haox.asn1.type.AbstractAsn1Type;
+import org.apache.haox.asn1.type.Asn1Item;
+import org.apache.haox.asn1.type.Asn1Type;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Asn1 decoder
+ */
+public class Asn1InputBuffer {
+    private final LimitedByteBuffer limitedBuffer;
+
+    public Asn1InputBuffer(byte[] bytes) {
+        this(new LimitedByteBuffer(bytes));
+    }
+
+    public Asn1InputBuffer(ByteBuffer byteBuffer) {
+        this(new LimitedByteBuffer(byteBuffer));
+    }
+
+    public Asn1InputBuffer(LimitedByteBuffer limitedByteBuffer) {
+        this.limitedBuffer = limitedByteBuffer;
+    }
+
+    public Asn1Type read() throws IOException {
+        if (! limitedBuffer.available()) {
+            return null;
+        }
+        Asn1Item one = AbstractAsn1Type.decodeOne(limitedBuffer);
+        if (one.isSimple()) {
+            one.decodeValueAsSimple();
+        } else if (one.isCollection()) {
+            one.decodeValueAsCollection();
+        }
+        if (one.isFullyDecoded()) {
+            return one.getValue();
+        }
+        return one;
+    }
+
+    public void readBytes(byte[] bytes) throws IOException {
+        limitedBuffer.readBytes(bytes);
+    }
+
+    public byte[] readAllLeftBytes() throws IOException {
+        return limitedBuffer.readAllLeftBytes();
+    }
+
+    public void skipNext() throws IOException {
+        if (limitedBuffer.available()) {
+            AbstractAsn1Type.skipOne(limitedBuffer);
+        }
+    }
+
+    public void skipBytes(int len) throws IOException {
+        if (limitedBuffer.available()) {
+            limitedBuffer.skip(len);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1OutputBuffer.java
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1OutputBuffer.java b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1OutputBuffer.java
new file mode 100644
index 0000000..e93b206
--- /dev/null
+++ b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/Asn1OutputBuffer.java
@@ -0,0 +1,53 @@
+package org.apache.haox.asn1;
+
+import org.apache.haox.asn1.type.AbstractAsn1Type;
+import org.apache.haox.asn1.type.Asn1Type;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Asn1 encoder
+ */
+public class Asn1OutputBuffer {
+    private List<Asn1Type> objects;
+
+    public Asn1OutputBuffer() {
+        this.objects = new ArrayList<Asn1Type>(3);
+    }
+
+    public void write(Asn1Type value) {
+        objects.add(value);
+    }
+
+    public void write(Asn1Type value, EncodingOption option) {
+        value.setEncodingOption(option);
+        objects.add(value);
+    }
+
+    public ByteBuffer getOutput() {
+        int len = encodingLength();
+        ByteBuffer byteBuffer = ByteBuffer.allocate(len);
+        encode(byteBuffer);
+        return byteBuffer;
+    }
+
+    private int encodingLength() {
+        int allLen = 0;
+        for (Asn1Type item : objects) {
+            if (item != null) {
+                allLen += ((AbstractAsn1Type) item).encodingLength();
+            }
+        }
+        return allLen;
+    }
+
+    private void encode(ByteBuffer buffer) {
+        for (Asn1Type item : objects) {
+            if (item != null) {
+                item.encode(buffer);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/EncodingOption.java
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/EncodingOption.java b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/EncodingOption.java
new file mode 100644
index 0000000..64fe9ab
--- /dev/null
+++ b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/EncodingOption.java
@@ -0,0 +1,65 @@
+package org.apache.haox.asn1;
+
+public enum EncodingOption
+{
+    UNKNOWN(-1),
+    PRIMITIVE(1),
+    CONSTRUCTED(2),
+    CONSTRUCTED_DEFLEN(3),
+    CONSTRUCTED_INDEFLEN(4),
+    IMPLICIT(5),
+    EXPLICIT(6),
+    BER(7),
+    DER(8),
+    CER(9);
+
+    private int value;
+
+    private EncodingOption(int value) {
+        this.value = value;
+    }
+
+    public static int CONSTRUCTED_FLAG = 0x20;
+
+    public static boolean isConstructed(int tag) {
+        return (tag & CONSTRUCTED_FLAG) != 0;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public boolean isPrimitive() {
+        return this == PRIMITIVE;
+    }
+
+    public boolean isConstructed() {
+        return this == CONSTRUCTED || this == CONSTRUCTED_DEFLEN || this == CONSTRUCTED_INDEFLEN;
+    }
+
+    public boolean isImplicit() {
+        return this == IMPLICIT;
+    }
+
+    public boolean isExplicit() {
+        return this == EXPLICIT;
+    }
+
+    public boolean isDer() {
+        return this == DER;
+    }
+
+    public boolean isCer() {
+        return this == CER;
+    }
+
+    public static EncodingOption fromValue(int value) {
+        for (EncodingOption e : values()) {
+            if (e.getValue() == value) {
+                return (EncodingOption) e;
+            }
+        }
+
+        return UNKNOWN;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/LimitedByteBuffer.java
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/LimitedByteBuffer.java b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/LimitedByteBuffer.java
new file mode 100644
index 0000000..43a1327
--- /dev/null
+++ b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/LimitedByteBuffer.java
@@ -0,0 +1,102 @@
+package org.apache.haox.asn1;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class LimitedByteBuffer {
+    private final ByteBuffer byteBuffer;
+    private final int limit;
+    private int startOffset;
+
+    public LimitedByteBuffer(byte[] bytes) {
+        this.byteBuffer = ByteBuffer.wrap(bytes);
+        this.limit = bytes.length;
+        this.startOffset = 0;
+    }
+
+    public LimitedByteBuffer(ByteBuffer byteBuffer) {
+        this(byteBuffer, byteBuffer.limit());
+    }
+
+    public LimitedByteBuffer(ByteBuffer byteBuffer, int limit) {
+        this.byteBuffer = byteBuffer;
+        this.limit = limit;
+        this.startOffset = byteBuffer.position();
+    }
+
+    public LimitedByteBuffer(LimitedByteBuffer other, int limit) {
+        if (limit > other.hasLeft()) {
+            throw new IllegalArgumentException("limit is too large, out of bound");
+        }
+        this.byteBuffer = other.byteBuffer.duplicate();
+        this.limit = limit;
+        this.startOffset = byteBuffer.position();
+    }
+
+    public boolean available() {
+        return byteBuffer.hasRemaining() &&
+                byteBuffer.position() - startOffset < limit;
+    }
+
+    public long hasRead() {
+        return byteBuffer.position() - startOffset;
+    }
+    public long hasLeft() {
+        return limit - hasRead();
+    }
+
+    public byte readByte() throws IOException {
+        if (!available()) {
+            throw new IOException("Buffer EOF");
+        }
+        return byteBuffer.get();
+    }
+
+    public byte[] readAllLeftBytes() throws IOException {
+        return readBytes((int) hasLeft());
+    }
+
+    public void skip(int len) throws IOException {
+        checkLen(len);
+        int newPos = byteBuffer.position() + len;
+        byteBuffer.position(newPos);
+    }
+
+    public byte[] readBytes(int len) throws IOException {
+        checkLen(len);
+
+        byte[] bytes = new byte[len];
+        if (len > 0) {
+            byteBuffer.get(bytes);
+        }
+        return bytes;
+    }
+
+    private void checkLen(int len) throws IOException {
+        if (len < 0) {
+            throw new IllegalArgumentException("Bad argument len: " + len);
+        }
+        if (len > 0) {
+            if (!available()) {
+                throw new IOException("Buffer EOF");
+            }
+            if (hasLeft() < len) {
+                throw new IOException("Out of Buffer");
+            }
+        }
+    }
+
+    public void readBytes(byte[] bytes) throws IOException {
+        if (bytes == null) {
+            throw new IllegalArgumentException("Bad argument bytes: null");
+        }
+        if (!available()) {
+            throw new IOException("Buffer EOF");
+        }
+        if (hasLeft() < bytes.length) {
+            throw new IOException("Out of Buffer");
+        }
+
+        byteBuffer.get(bytes);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/TagClass.java
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/TagClass.java b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/TagClass.java
new file mode 100644
index 0000000..9f393e1
--- /dev/null
+++ b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/TagClass.java
@@ -0,0 +1,55 @@
+package org.apache.haox.asn1;
+
+public enum TagClass {
+    UNKNOWN(-1),
+    UNIVERSAL(0x00),
+    APPLICATION(0x40),
+    CONTEXT_SPECIFIC(0x80),
+    PRIVATE(0xC0);
+
+    private int value;
+
+    private TagClass(int value) {
+        this.value = value;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public boolean isUniversal() {
+        return this == UNIVERSAL;
+    }
+
+    public boolean isAppSpecific() {
+        return this == APPLICATION;
+    }
+
+    public boolean isContextSpecific() {
+        return this == CONTEXT_SPECIFIC;
+    }
+
+    public boolean isTagged() {
+        return this == APPLICATION || this == CONTEXT_SPECIFIC;
+    }
+
+    public static TagClass fromValue(int value) {
+        // Optimized by Emmanuel
+        switch (value) {
+            case 0x00:
+                return TagClass.UNIVERSAL;
+            case 0x40:
+                return TagClass.APPLICATION;
+            case 0x80:
+                return TagClass.CONTEXT_SPECIFIC;
+            case 0xC0:
+                return TagClass.PRIVATE;
+            default:
+                return TagClass.UNKNOWN;
+        }
+    }
+
+    public static TagClass fromTagFlags(int tag) {
+        return fromValue(tag & 0xC0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/TaggingOption.java
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/TaggingOption.java b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/TaggingOption.java
new file mode 100644
index 0000000..431c184
--- /dev/null
+++ b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/TaggingOption.java
@@ -0,0 +1,49 @@
+package org.apache.haox.asn1;
+
+public class TaggingOption
+{
+    private int tagNo;
+    private boolean isImplicit;
+    private boolean isAppSpecific;
+
+    public static TaggingOption newImplicitAppSpecific(int tagNo) {
+        return new TaggingOption(tagNo, true, true);
+    }
+
+    public static TaggingOption newExplicitAppSpecific(int tagNo) {
+        return new TaggingOption(tagNo, false, true);
+    }
+
+    public static TaggingOption newImplicitContextSpecific(int tagNo) {
+        return new TaggingOption(tagNo, true, false);
+    }
+
+    public static TaggingOption newExplicitContextSpecific(int tagNo) {
+        return new TaggingOption(tagNo, false, false);
+    }
+
+    private TaggingOption(int tagNo, boolean isImplicit, boolean isAppSpecific) {
+        this.tagNo = tagNo;
+        this.isImplicit = isImplicit;
+        this.isAppSpecific = isAppSpecific;
+    }
+
+    public int tagFlags(boolean isTaggedConstructed) {
+        boolean isConstructed = isImplicit ? isTaggedConstructed : true;
+        TagClass tagClass = isAppSpecific ? TagClass.APPLICATION : TagClass.CONTEXT_SPECIFIC;
+        int flags = tagClass.getValue() | (isConstructed ? EncodingOption.CONSTRUCTED_FLAG : 0x00);
+        return flags;
+    }
+
+    public int getTagNo() {
+        return tagNo;
+    }
+
+    public boolean isAppSpecific() {
+        return isAppSpecific;
+    }
+
+    public boolean isImplicit() {
+        return isImplicit;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/UniversalTag.java
----------------------------------------------------------------------
diff --git a/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/UniversalTag.java b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/UniversalTag.java
new file mode 100644
index 0000000..629d68b
--- /dev/null
+++ b/contrib/haox-asn1/src/main/java/org/apache/haox/asn1/UniversalTag.java
@@ -0,0 +1,87 @@
+package org.apache.haox.asn1;
+
+// Optimized by Emmanuel
+public enum UniversalTag {
+    UNKNOWN             (-1),
+    CHOICE              (-2), // Only for internal using
+    BOOLEAN             (0x01),
+    INTEGER             (0x02),
+    BIT_STRING          (0x03),
+    OCTET_STRING        (0x04),
+    NULL                (0x05),
+    OBJECT_IDENTIFIER   (0x06),
+    OBJECT_DESCRIPTOR   (0x07),     // Added for completness
+    EXTERNAL            (0x08),
+    REAL                (0x09),
+    ENUMERATED          (0x0a),
+    EMBEDDED_PDV        (0x0b),     // Added for completness
+    UTF8_STRING         (0x0c),
+    RELATIVE_OID        (0x0d),     // Added for completness
+    RESERVED_14         (0x0e),     // Added for completness
+    RESERVED_15         (0x0f),     // Added for completness
+    SEQUENCE            (0x10),
+    SEQUENCE_OF         (0x10),
+    SET                 (0x11),
+    SET_OF              (0x11),
+    NUMERIC_STRING      (0x12),
+    PRINTABLE_STRING    (0x13),
+    T61_STRING          (0x14),
+    VIDEOTEX_STRING     (0x15),
+    IA5_STRING          (0x16),
+    UTC_TIME            (0x17),
+    GENERALIZED_TIME    (0x18),
+    GRAPHIC_STRING      (0x19),
+    VISIBLE_STRING      (0x1a),
+    GENERAL_STRING      (0x1b),
+    UNIVERSAL_STRING    (0x1c),
+    CHARACTER_STRING    (0x1d),     // Added for completness
+    BMP_STRING          (0x1e),
+    RESERVED_31         (0x1f);     // Added for completness
+
+    private int value;
+
+    private UniversalTag(int value) {
+        this.value = value;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public static UniversalTag fromValue(int value) {
+        switch (value) {
+            case 0x01 : return BOOLEAN;
+            case 0x02 : return INTEGER;
+            case 0x03 : return BIT_STRING;
+            case 0x04 : return OCTET_STRING;
+            case 0x05 : return NULL;
+            case 0x06 : return OBJECT_IDENTIFIER;
+            case 0x07 : return OBJECT_DESCRIPTOR;
+            case 0x08 : return EXTERNAL;
+            case 0x09 : return REAL;
+            case 0x0A : return ENUMERATED;
+            case 0x0B : return EMBEDDED_PDV;
+            case 0x0C : return UTF8_STRING;
+            case 0x0D : return RELATIVE_OID;
+            case 0x0E : return RESERVED_14;
+            case 0x0F : return RESERVED_15;
+            case 0x10 : return SEQUENCE;
+            case 0x11 : return SET;
+            case 0x12 : return NUMERIC_STRING;
+            case 0x13 : return PRINTABLE_STRING;
+            case 0x14 : return T61_STRING;
+            case 0x15 : return VIDEOTEX_STRING;
+            case 0x16 : return IA5_STRING;
+            case 0x17 : return UTC_TIME;
+            case 0x18 : return GENERALIZED_TIME;
+            case 0x19 : return GRAPHIC_STRING;
+            case 0x1A : return VISIBLE_STRING;
+            case 0x1B : return GENERAL_STRING;
+            case 0x1C : return UNIVERSAL_STRING;
+            case 0x1D : return CHARACTER_STRING;
+            case 0x1E : return BMP_STRING;
+            case 0x1F : return RESERVED_31;
+            default : return UNKNOWN;
+        }
+    }
+}