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:30:54 UTC

[10/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/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacDataInputStream.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacDataInputStream.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacDataInputStream.java
new file mode 100644
index 0000000..c668133
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacDataInputStream.java
@@ -0,0 +1,139 @@
+package org.apache.kerberos.kerb.codec.pac;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.Date;
+
+public class PacDataInputStream {
+
+    private DataInputStream dis;
+    private int size;
+
+    public PacDataInputStream(InputStream in) throws IOException {
+        dis = new DataInputStream(in);
+        size = in.available();
+    }
+
+    public void align(int mask) throws IOException {
+        int position = size - dis.available();
+        int shift = position & mask - 1;
+        if(mask != 0 && shift != 0)
+            dis.skip(mask - shift);
+    }
+
+    public int available() throws IOException {
+        return dis.available();
+    }
+
+    public void readFully(byte[] b) throws IOException {
+        dis.readFully(b);
+    }
+
+    public void readFully(byte[] b, int off, int len) throws IOException {
+        dis.readFully(b, off, len);
+    }
+
+    public char readChar() throws IOException {
+        align(2);
+        return dis.readChar();
+    }
+
+    public byte readByte() throws IOException {
+        return dis.readByte();
+    }
+
+    public short readShort() throws IOException {
+        align(2);
+        return Short.reverseBytes((short)dis.readShort());
+    }
+
+    public int readInt() throws IOException {
+        align(4);
+        return Integer.reverseBytes(dis.readInt());
+    }
+
+    public long readLong() throws IOException {
+        align(8);
+        return Long.reverseBytes(dis.readLong());
+    }
+
+    public int readUnsignedByte() throws IOException {
+        return ((int)readByte()) & 0xff;
+    }
+
+    public long readUnsignedInt() throws IOException {
+        return ((long)readInt()) & 0xffffffffL;
+    }
+
+    public int readUnsignedShort() throws IOException {
+        return ((int)readShort()) & 0xffff;
+    }
+
+    public Date readFiletime() throws IOException {
+        Date date = null;
+
+        long last = readUnsignedInt();
+        long first = readUnsignedInt();
+        if(first != 0x7fffffffL && last != 0xffffffffL) {
+            BigInteger lastBigInt = BigInteger.valueOf(last);
+            BigInteger firstBigInt = BigInteger.valueOf(first);
+            BigInteger completeBigInt = lastBigInt.add(firstBigInt.shiftLeft(32));
+            completeBigInt = completeBigInt.divide(BigInteger.valueOf(10000L));
+            completeBigInt = completeBigInt.add(BigInteger.valueOf(PacConstants.FILETIME_BASE));
+            date = new Date(completeBigInt.longValue());
+        }
+
+        return date;
+    }
+
+    public PacUnicodeString readUnicodeString() throws IOException {
+        short length = readShort();
+        short maxLength = readShort();
+        int pointer = readInt();
+
+        if(maxLength < length) {
+            throw new IOException("pac.string.malformed.size");
+        }
+
+        return new PacUnicodeString(length, maxLength, pointer);
+    }
+
+    public String readString() throws IOException {
+        int totalChars = readInt();
+        int unusedChars = readInt();
+        int usedChars = readInt();
+
+        if(unusedChars > totalChars || usedChars > totalChars - unusedChars)
+            throw new IOException("pac.string.malformed.size");
+
+        dis.skip(unusedChars * 2);
+        char[] chars = new char[usedChars];
+        for(int l = 0; l < usedChars; l++)
+            chars[l] = (char)readShort();
+
+        return new String(chars);
+    }
+
+    public PacSid readId() throws IOException {
+        byte[] bytes = new byte[4];
+        readFully(bytes);
+
+        return PacSid.createFromSubs(bytes);
+    }
+
+    public PacSid readSid() throws IOException {
+        int sidSize = readInt();
+
+        byte[] bytes = new byte[8 + sidSize * 4];
+        readFully(bytes);
+
+        return new PacSid(bytes);
+    }
+
+    public int skipBytes(int n) throws IOException {
+        return dis.skipBytes(n);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacGroup.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacGroup.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacGroup.java
new file mode 100644
index 0000000..73a2c18
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacGroup.java
@@ -0,0 +1,22 @@
+package org.apache.kerberos.kerb.codec.pac;
+
+public class PacGroup {
+
+    private PacSid id;
+    private int attributes;
+
+    public PacGroup(PacSid id, int attributes) {
+        super();
+        this.id = id;
+        this.attributes = attributes;
+    }
+
+    public PacSid getId() {
+        return id;
+    }
+
+    public int getAttributes() {
+        return attributes;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacLogonInfo.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacLogonInfo.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacLogonInfo.java
new file mode 100644
index 0000000..972d6d6
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacLogonInfo.java
@@ -0,0 +1,303 @@
+package org.apache.kerberos.kerb.codec.pac;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Date;
+
+public class PacLogonInfo {
+
+    private Date logonTime;
+    private Date logoffTime;
+    private Date kickOffTime;
+    private Date pwdLastChangeTime;
+    private Date pwdCanChangeTime;
+    private Date pwdMustChangeTime;
+    private short logonCount;
+    private short badPasswordCount;
+    private String userName;
+    private String userDisplayName;
+    private String logonScript;
+    private String profilePath;
+    private String homeDirectory;
+    private String homeDrive;
+    private String serverName;
+    private String domainName;
+    private PacSid userSid;
+    private PacSid groupSid;
+    private PacSid[] groupSids;
+    private PacSid[] resourceGroupSids;
+    private PacSid[] extraSids;
+    private int userAccountControl;
+    private int userFlags;
+
+    public PacLogonInfo(byte[] data) throws IOException {
+        try {
+            PacDataInputStream pacStream = new PacDataInputStream(new DataInputStream(
+                    new ByteArrayInputStream(data)));
+
+            // Skip firsts
+            pacStream.skipBytes(20);
+
+            // Dates
+            logonTime = pacStream.readFiletime();
+            logoffTime = pacStream.readFiletime();
+            kickOffTime = pacStream.readFiletime();
+            pwdLastChangeTime = pacStream.readFiletime();
+            pwdCanChangeTime = pacStream.readFiletime();
+            pwdMustChangeTime = pacStream.readFiletime();
+
+            // User related strings as UnicodeStrings
+            PacUnicodeString userNameString = pacStream.readUnicodeString();
+            PacUnicodeString userDisplayNameString = pacStream.readUnicodeString();
+            PacUnicodeString logonScriptString = pacStream.readUnicodeString();
+            PacUnicodeString profilePathString = pacStream.readUnicodeString();
+            PacUnicodeString homeDirectoryString = pacStream.readUnicodeString();
+            PacUnicodeString homeDriveString = pacStream.readUnicodeString();
+
+            // Some counts
+            logonCount = pacStream.readShort();
+            badPasswordCount = pacStream.readShort();
+
+            // IDs for user
+            PacSid userId = pacStream.readId();
+            PacSid groupId = pacStream.readId();
+
+            // Groups information
+            int groupCount = pacStream.readInt();
+            int groupPointer = pacStream.readInt();
+
+            // User flags about PAC Logon Info content
+            userFlags = pacStream.readInt();
+            boolean hasExtraSids = (userFlags & PacConstants.LOGON_EXTRA_SIDS) == PacConstants.LOGON_EXTRA_SIDS;
+            boolean hasResourceGroups = (userFlags & PacConstants.LOGON_RESOURCE_GROUPS) == PacConstants.LOGON_RESOURCE_GROUPS;
+
+            // Skip some reserved fields (User Session Key)
+            pacStream.skipBytes(16);
+
+            // Server related strings as UnicodeStrings
+            PacUnicodeString serverNameString = pacStream.readUnicodeString();
+            PacUnicodeString domainNameString = pacStream.readUnicodeString();
+
+            // ID for domain (used with relative IDs to get SIDs)
+            int domainIdPointer = pacStream.readInt();
+
+            // Skip some reserved fields
+            pacStream.skipBytes(8);
+
+            userAccountControl = pacStream.readInt();
+
+            // Skip some reserved fields
+            pacStream.skipBytes(28);
+
+            // Extra SIDs information
+            int extraSidCount = pacStream.readInt();
+            int extraSidPointer = pacStream.readInt();
+
+            // ID for resource groups domain (used with IDs to get SIDs)
+            int resourceDomainIdPointer = pacStream.readInt();
+
+            // Resource groups information
+            int resourceGroupCount = pacStream.readInt();
+            int resourceGroupPointer = pacStream.readInt();
+
+            // User related strings
+            userName = userNameString.check(pacStream.readString());
+            userDisplayName = userDisplayNameString.check(pacStream.readString());
+            logonScript = logonScriptString.check(pacStream.readString());
+            profilePath = profilePathString.check(pacStream.readString());
+            homeDirectory = homeDirectoryString.check(pacStream.readString());
+            homeDrive = homeDriveString.check(pacStream.readString());
+
+            // Groups data
+            PacGroup[] groups = new PacGroup[0];
+            if(groupPointer != 0) {
+                int realGroupCount = pacStream.readInt();
+                if(realGroupCount != groupCount) {
+                    Object[] args = new Object[]{groupCount, realGroupCount};
+                    throw new IOException("pac.groups.invalid.size");
+                }
+                groups = new PacGroup[groupCount];
+                for(int i = 0; i < groupCount; i++) {
+                    pacStream.align(4);
+                    PacSid id = pacStream.readId();
+                    int attributes = pacStream.readInt();
+                    groups[i] = new PacGroup(id, attributes);
+                }
+            }
+
+            // Server related strings
+            serverName = serverNameString.check(pacStream.readString());
+            domainName = domainNameString.check(pacStream.readString());
+
+            // ID for domain (used with relative IDs to get SIDs)
+            PacSid domainId = null;
+            if(domainIdPointer != 0)
+                domainId = pacStream.readSid();
+
+            // Extra SIDs data
+            PacSidAttributes[] extraSidAtts = new PacSidAttributes[0];
+            if(hasExtraSids && extraSidPointer != 0) {
+                int realExtraSidCount = pacStream.readInt();
+                if(realExtraSidCount != extraSidCount) {
+                    Object[] args = new Object[]{extraSidCount, realExtraSidCount};
+                    throw new IOException("pac.extrasids.invalid.size");
+                }
+                extraSidAtts = new PacSidAttributes[extraSidCount];
+                int[] pointers = new int[extraSidCount];
+                int[] attributes = new int[extraSidCount];
+                for(int i = 0; i < extraSidCount; i++) {
+                    pointers[i] = pacStream.readInt();
+                    attributes[i] = pacStream.readInt();
+                }
+                for(int i = 0; i < extraSidCount; i++) {
+                    PacSid sid = (pointers[i] != 0) ? pacStream.readSid() : null;
+                    extraSidAtts[i] = new PacSidAttributes(sid, attributes[i]);
+                }
+            }
+
+            // ID for resource domain (used with relative IDs to get SIDs)
+            PacSid resourceDomainId = null;
+            if(resourceDomainIdPointer != 0)
+                resourceDomainId = pacStream.readSid();
+
+            // Resource groups data
+            PacGroup[] resourceGroups = new PacGroup[0];
+            if(hasResourceGroups && resourceGroupPointer != 0) {
+                int realResourceGroupCount = pacStream.readInt();
+                if(realResourceGroupCount != resourceGroupCount) {
+                    Object[] args = new Object[]{resourceGroupCount, realResourceGroupCount};
+                    throw new IOException("pac.resourcegroups.invalid.size");
+                }
+                resourceGroups = new PacGroup[resourceGroupCount];
+                for(int i = 0; i < resourceGroupCount; i++) {
+                    PacSid id = pacStream.readSid();
+                    int attributes = pacStream.readInt();
+                    resourceGroups[i] = new PacGroup(id, attributes);
+                }
+            }
+
+            // Extract Extra SIDs
+            extraSids = new PacSid[extraSidAtts.length];
+            for(int i = 0; i < extraSidAtts.length; i++) {
+                extraSids[i] = extraSidAtts[i].getId();
+            }
+
+            // Compute Resource Group IDs with Resource Domain ID to get SIDs
+            resourceGroupSids = new PacSid[resourceGroups.length];
+            for(int i = 0; i < resourceGroups.length; i++) {
+                resourceGroupSids[i] = PacSid.append(resourceDomainId, resourceGroups[i].getId());
+            }
+
+            // Compute User IDs with Domain ID to get User SIDs
+            // First extra is user if userId is empty
+            if(!userId.isEmpty() && !userId.isBlank()) {
+                userSid = PacSid.append(domainId, userId);
+            } else if(extraSids.length > 0) {
+                userSid = extraSids[0];
+            }
+            groupSid = PacSid.append(domainId, groupId);
+
+            // Compute Group IDs with Domain ID to get Group SIDs
+            groupSids = new PacSid[groups.length];
+            for(int i = 0; i < groups.length; i++) {
+                groupSids[i] = PacSid.append(domainId, groups[i].getId());
+            }
+        } catch(IOException e) {
+            throw new IOException("pac.logoninfo.malformed", e);
+        }
+    }
+
+    public Date getLogonTime() {
+        return logonTime;
+    }
+
+    public Date getLogoffTime() {
+        return logoffTime;
+    }
+
+    public Date getKickOffTime() {
+        return kickOffTime;
+    }
+
+    public Date getPwdLastChangeTime() {
+        return pwdLastChangeTime;
+    }
+
+    public Date getPwdCanChangeTime() {
+        return pwdCanChangeTime;
+    }
+
+    public Date getPwdMustChangeTime() {
+        return pwdMustChangeTime;
+    }
+
+    public short getLogonCount() {
+        return logonCount;
+    }
+
+    public short getBadPasswordCount() {
+        return badPasswordCount;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public String getUserDisplayName() {
+        return userDisplayName;
+    }
+
+    public String getLogonScript() {
+        return logonScript;
+    }
+
+    public String getProfilePath() {
+        return profilePath;
+    }
+
+    public String getHomeDirectory() {
+        return homeDirectory;
+    }
+
+    public String getHomeDrive() {
+        return homeDrive;
+    }
+
+    public String getServerName() {
+        return serverName;
+    }
+
+    public String getDomainName() {
+        return domainName;
+    }
+
+    public PacSid getUserSid() {
+        return userSid;
+    }
+
+    public PacSid getGroupSid() {
+        return groupSid;
+    }
+
+    public PacSid[] getGroupSids() {
+        return groupSids;
+    }
+
+    public PacSid[] getResourceGroupSids() {
+        return resourceGroupSids;
+    }
+
+    public PacSid[] getExtraSids() {
+        return extraSids;
+    }
+
+    public int getUserAccountControl() {
+        return userAccountControl;
+    }
+
+    public int getUserFlags() {
+        return userFlags;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSid.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSid.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSid.java
new file mode 100644
index 0000000..1262e52
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSid.java
@@ -0,0 +1,111 @@
+package org.apache.kerberos.kerb.codec.pac;
+
+import java.io.IOException;
+
+public class PacSid {
+
+    private static final String FORMAT = "%1$02x";
+
+    private byte revision;
+    private byte subCount;
+    private byte[] authority;
+    private byte[] subs;
+
+    public PacSid(byte[] bytes) throws IOException {
+        if(bytes.length < 8 || ((bytes.length - 8) % 4) != 0
+                || ((bytes.length - 8) / 4) != bytes[1])
+            throw new IOException("pac.sid.malformed.size");
+
+        this.revision = bytes[0];
+        this.subCount = bytes[1];
+        this.authority = new byte[6];
+        System.arraycopy(bytes, 2, this.authority, 0, 6);
+        this.subs = new byte[bytes.length - 8];
+        System.arraycopy(bytes, 8, this.subs, 0, bytes.length - 8);
+    }
+
+    public PacSid(PacSid sid) {
+        this.revision = sid.revision;
+        this.subCount = sid.subCount;
+        this.authority = new byte[6];
+        System.arraycopy(sid.authority, 0, this.authority, 0, 6);
+        this.subs = new byte[sid.subs.length];
+        System.arraycopy(sid.subs, 0, this.subs, 0, sid.subs.length);
+    }
+
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("\\").append(String.format(FORMAT, ((int)revision) & 0xff));
+        builder.append("\\").append(String.format(FORMAT, ((int)subCount) & 0xff));
+        for(int i = 0; i < authority.length; i++) {
+            int unsignedByte = ((int)authority[i]) & 0xff;
+            builder.append("\\").append(String.format(FORMAT, unsignedByte));
+        }
+        for(int i = 0; i < subs.length; i++) {
+            int unsignedByte = ((int)subs[i]) & 0xff;
+            builder.append("\\").append(String.format(FORMAT, unsignedByte));
+        }
+
+        return builder.toString();
+    }
+
+    public boolean isEmpty() {
+        return subCount == 0;
+    }
+
+    public boolean isBlank() {
+        boolean blank = true;
+        for(byte sub : subs)
+            blank = blank && (sub == 0);
+        return blank;
+    }
+
+    public byte[] getBytes() {
+        byte[] bytes = new byte[8 + subCount * 4];
+        bytes[0] = revision;
+        bytes[1] = subCount;
+        System.arraycopy(authority, 0, bytes, 2, 6);
+        System.arraycopy(subs, 0, bytes, 8, subs.length);
+
+        return bytes;
+    }
+
+    public static String toString(byte[] bytes) {
+        StringBuilder builder = new StringBuilder();
+
+        for(int i = 0; i < bytes.length; i++) {
+            int unsignedByte = ((int)bytes[i]) & 0xff;
+            builder.append("\\").append(String.format(FORMAT, unsignedByte));
+        }
+
+        return builder.toString();
+    }
+
+    public static PacSid createFromSubs(byte[] bytes) throws IOException {
+        if((bytes.length % 4) != 0) {
+            Object[] args = new Object[]{bytes.length};
+            throw new IOException("pac.subauthority.malformed.size");
+        }
+
+        byte[] sidBytes = new byte[8 + bytes.length];
+        sidBytes[0] = 1;
+        sidBytes[1] = (byte)(bytes.length / 4);
+        System.arraycopy(new byte[]{0, 0, 0, 0, 0, 5}, 0, sidBytes, 2, 6);
+        System.arraycopy(bytes, 0, sidBytes, 8, bytes.length);
+
+        return new PacSid(sidBytes);
+    }
+
+    public static PacSid append(PacSid sid1, PacSid sid2) {
+        PacSid sid = new PacSid(sid1);
+
+        sid.subCount += sid2.subCount;
+        sid.subs = new byte[sid.subCount * 4];
+        System.arraycopy(sid1.subs, 0, sid.subs, 0, sid1.subs.length);
+        System.arraycopy(sid2.subs, 0, sid.subs, sid1.subs.length, sid2.subs.length);
+
+        return sid;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSidAttributes.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSidAttributes.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSidAttributes.java
new file mode 100644
index 0000000..0e72278
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSidAttributes.java
@@ -0,0 +1,22 @@
+package org.apache.kerberos.kerb.codec.pac;
+
+public class PacSidAttributes {
+
+    private PacSid id;
+    private int attributes;
+
+    public PacSidAttributes(PacSid id, int attributes) {
+        super();
+        this.id = id;
+        this.attributes = attributes;
+    }
+
+    public PacSid getId() {
+        return id;
+    }
+
+    public int getAttributes() {
+        return attributes;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSignature.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSignature.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSignature.java
new file mode 100644
index 0000000..cffa307
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacSignature.java
@@ -0,0 +1,33 @@
+package org.apache.kerberos.kerb.codec.pac;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+public class PacSignature {
+
+    private int type;
+    private byte[] checksum;
+
+    public PacSignature(byte[] data) throws IOException {
+        try {
+            PacDataInputStream bufferStream = new PacDataInputStream(new DataInputStream(
+                    new ByteArrayInputStream(data)));
+
+            type = bufferStream.readInt();
+            checksum = new byte[bufferStream.available()];
+            bufferStream.readFully(checksum);
+        } catch(IOException e) {
+            throw new IOException("pac.signature.malformed", e);
+        }
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    public byte[] getChecksum() {
+        return checksum;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacUnicodeString.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacUnicodeString.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacUnicodeString.java
new file mode 100644
index 0000000..3bc5879
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/pac/PacUnicodeString.java
@@ -0,0 +1,42 @@
+package org.apache.kerberos.kerb.codec.pac;
+
+import java.io.IOException;
+
+public class PacUnicodeString {
+
+    private short length;
+    private short maxLength;
+    private int pointer;
+
+    public PacUnicodeString(short length, short maxLength, int pointer) {
+        super();
+        this.length = length;
+        this.maxLength = maxLength;
+        this.pointer = pointer;
+    }
+
+    public short getLength() {
+        return length;
+    }
+
+    public short getMaxLength() {
+        return maxLength;
+    }
+
+    public int getPointer() {
+        return pointer;
+    }
+
+    public String check(String string) throws IOException {
+        if(pointer == 0 && string != null)
+            throw new IOException("pac.string.notempty");
+
+        int expected = length / 2;
+        if(string.length() != expected) {
+            Object[] args = new Object[]{expected, string.length()};
+            throw new IOException("pac.string.invalid.size");
+        }
+
+        return string;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoConstants.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoConstants.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoConstants.java
new file mode 100644
index 0000000..2bf0116
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoConstants.java
@@ -0,0 +1,12 @@
+package org.apache.kerberos.kerb.codec.spnego;
+
+public interface SpnegoConstants {
+
+    static final String SPNEGO_MECHANISM = "1.3.6.1.5.5.2";
+    static final String KERBEROS_MECHANISM = "1.2.840.113554.1.2.2";
+    static final String LEGACY_KERBEROS_MECHANISM = "1.2.840.48018.1.2.2";
+    static final String NTLMSSP_MECHANISM = "1.3.6.1.4.1.311.2.2.10";
+
+    static final String SPNEGO_OID = SPNEGO_MECHANISM;
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoInitToken.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoInitToken.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoInitToken.java
new file mode 100644
index 0000000..7faf764
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoInitToken.java
@@ -0,0 +1,34 @@
+package org.apache.kerberos.kerb.codec.spnego;
+
+import java.io.IOException;
+
+public class SpnegoInitToken extends SpnegoToken {
+
+    public static final int DELEGATION = 0x40;
+    public static final int MUTUAL_AUTHENTICATION = 0x20;
+    public static final int REPLAY_DETECTION = 0x10;
+    public static final int SEQUENCE_CHECKING = 0x08;
+    public static final int ANONYMITY = 0x04;
+    public static final int CONFIDENTIALITY = 0x02;
+    public static final int INTEGRITY = 0x01;
+
+    private String[] mechanisms;
+    private int contextFlags;
+
+    public SpnegoInitToken(byte[] token) throws IOException {
+
+    }
+
+    public int getContextFlags() {
+        return contextFlags;
+    }
+
+    public boolean getContextFlag(int flag) {
+        return (getContextFlags() & flag) == flag;
+    }
+
+    public String[] getMechanisms() {
+        return mechanisms;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoTargToken.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoTargToken.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoTargToken.java
new file mode 100644
index 0000000..5255649
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoTargToken.java
@@ -0,0 +1,22 @@
+package org.apache.kerberos.kerb.codec.spnego;
+
+import java.io.IOException;
+
+public class SpnegoTargToken extends SpnegoToken {
+
+    public static final int UNSPECIFIED_RESULT = -1;
+    public static final int ACCEPT_COMPLETED = 0;
+    public static final int ACCEPT_INCOMPLETE = 1;
+    public static final int REJECTED = 2;
+
+    private int result = UNSPECIFIED_RESULT;
+
+    public SpnegoTargToken(byte[] token) throws IOException {
+
+    }
+
+    public int getResult() {
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoToken.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoToken.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoToken.java
new file mode 100644
index 0000000..65ed48e
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/spnego/SpnegoToken.java
@@ -0,0 +1,48 @@
+package org.apache.kerberos.kerb.codec.spnego;
+
+import java.io.IOException;
+
+public abstract class SpnegoToken {
+
+    // Default max size as 65K
+    public static int TOKEN_MAX_SIZE = 66560;
+
+    protected byte[] mechanismToken;
+    protected byte[] mechanismList;
+    protected String mechanism;
+
+    public static SpnegoToken parse(byte[] token) throws IOException {
+        SpnegoToken spnegoToken = null;
+
+        if(token.length <= 0)
+            throw new IOException("spnego.token.empty");
+
+        switch (token[0]) {
+        case (byte)0x60:
+            spnegoToken = new SpnegoInitToken(token);
+            break;
+        case (byte)0xa1:
+            spnegoToken = new SpnegoTargToken(token);
+            break;
+        default:
+            spnegoToken = null;
+            Object[] args = new Object[]{token[0]};
+            throw new IOException("spnego.token.invalid");
+        }
+
+        return spnegoToken;
+    }
+
+    public byte[] getMechanismToken() {
+        return mechanismToken;
+    }
+
+    public byte[] getMechanismList() {
+        return mechanismList;
+    }
+
+    public String getMechanism() {
+        return mechanism;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/CodecTest.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/CodecTest.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/CodecTest.java
new file mode 100644
index 0000000..9c1d1ca
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/CodecTest.java
@@ -0,0 +1,27 @@
+package org.apache.kerberos.kerb.codec.test;
+
+import junit.framework.Assert;
+import org.apache.kerberos.kerb.KrbException;
+import org.apache.kerberos.kerb.codec.KrbCodec;
+import org.apache.kerberos.kerb.spec.common.CheckSum;
+import org.apache.kerberos.kerb.spec.common.CheckSumType;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class CodecTest {
+
+    @Test
+    public void testCodec() throws KrbException {
+        CheckSum mcs = new CheckSum();
+        mcs.setCksumtype(CheckSumType.CRC32);
+        mcs.setChecksum(new byte[] {0x10});
+        byte[] bytes = KrbCodec.encode(mcs);
+        Assert.assertNotNull(bytes);
+
+        CheckSum restored = KrbCodec.decode(bytes, CheckSum.class);
+        Assert.assertNotNull(restored);
+        Assert.assertEquals(mcs.getCksumtype(), restored.getCksumtype());
+        Assert.assertTrue(Arrays.equals(mcs.getChecksum(), restored.getChecksum()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestKerberos.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestKerberos.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestKerberos.java
new file mode 100644
index 0000000..c489fe5
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestKerberos.java
@@ -0,0 +1,248 @@
+package org.apache.kerberos.kerb.codec.test;
+
+import org.apache.kerberos.kerb.codec.kerberos.AuthzDataUtil;
+import org.apache.kerberos.kerb.codec.kerberos.KerberosCredentials;
+import org.apache.kerberos.kerb.codec.kerberos.KerberosTicket;
+import org.apache.kerberos.kerb.codec.kerberos.KerberosToken;
+import org.apache.kerberos.kerb.codec.pac.Pac;
+import org.apache.kerberos.kerb.codec.pac.PacLogonInfo;
+import org.apache.kerberos.kerb.codec.pac.PacSid;
+import org.apache.kerberos.kerb.spec.common.AuthorizationData;
+import org.apache.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerberos.kerb.spec.common.EncryptionType;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class TestKerberos {
+
+    private byte[] rc4Token;
+    private byte[] desToken;
+    private byte[] aes128Token;
+    private byte[] aes256Token;
+    private byte[] corruptToken;
+    private EncryptionKey rc4Key;
+    private EncryptionKey desKey;
+    private EncryptionKey aes128Key;
+    private EncryptionKey aes256Key;
+    private EncryptionKey corruptKey;
+
+    @Before
+    public void setUp() throws IOException {
+        InputStream file;
+        byte[] keyData;
+
+        file = this.getClass().getClassLoader().getResourceAsStream("rc4-kerberos-data");
+        rc4Token = new byte[file.available()];
+        file.read(rc4Token);
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("des-kerberos-data");
+        desToken = new byte[file.available()];
+        file.read(desToken);
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("aes128-kerberos-data");
+        aes128Token = new byte[file.available()];
+        file.read(aes128Token);
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("aes256-kerberos-data");
+        aes256Token = new byte[file.available()];
+        file.read(aes256Token);
+        file.close();
+
+        corruptToken = new byte[]{1, 2, 3, 4, 5, 6};
+
+        file = this.getClass().getClassLoader().getResourceAsStream("rc4-key-data");
+        keyData = new byte[file.available()];
+        file.read(keyData);
+        rc4Key = new EncryptionKey(23, keyData, 2);
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("des-key-data");
+        keyData = new byte[file.available()];
+        file.read(keyData);
+        desKey = new EncryptionKey(3, keyData, 2);
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("aes128-key-data");
+        keyData = new byte[file.available()];
+        file.read(keyData);
+        aes128Key = new EncryptionKey(17, keyData, 2);
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("aes256-key-data");
+        keyData = new byte[file.available()];
+        file.read(keyData);
+        aes256Key = new EncryptionKey(18, keyData, 2);
+        file.close();
+
+        corruptKey = new EncryptionKey(23, new byte[]{5, 4, 2, 1, 5, 4, 2, 1, 3}, 2);
+    }
+
+    @Test
+    public void testRc4Ticket() throws Exception {
+        KerberosToken token = new KerberosToken(rc4Token, rc4Key);
+
+        Assert.assertNotNull(token);
+        Assert.assertNotNull(token.getApRequest());
+
+        KerberosTicket ticket = token.getApRequest().getTicket();
+        Assert.assertNotNull(ticket);
+        Assert.assertEquals("HTTP/server.test.domain.com", ticket.getServerPrincipalName());
+        Assert.assertEquals("DOMAIN.COM", ticket.getServerRealm());
+        Assert.assertEquals("user.test", ticket.getUserPrincipalName());
+        Assert.assertEquals("DOMAIN.COM", ticket.getUserRealm());
+    }
+
+    //@Test
+    public void testDesTicket() throws Exception {
+        KerberosToken token = new KerberosToken(desToken, desKey);
+
+        Assert.assertNotNull(token);
+        Assert.assertNotNull(token.getApRequest());
+
+        KerberosTicket ticket = token.getApRequest().getTicket();
+        Assert.assertNotNull(ticket);
+        Assert.assertEquals("HTTP/server.test.domain.com", ticket.getServerPrincipalName());
+        Assert.assertEquals("DOMAIN.COM", ticket.getServerRealm());
+        Assert.assertEquals("user.test@domain.com", ticket.getUserPrincipalName());
+        Assert.assertEquals("DOMAIN.COM", ticket.getUserRealm());
+    }
+
+    @Test
+    public void testAes128Ticket() throws Exception {
+        KerberosToken token = null;
+        token = new KerberosToken(aes128Token, aes128Key);
+
+        Assert.assertNotNull(token);
+        Assert.assertNotNull(token.getApRequest());
+
+        KerberosTicket ticket = token.getApRequest().getTicket();
+        Assert.assertNotNull(ticket);
+        Assert.assertEquals("HTTP/server.test.domain.com", ticket.getServerPrincipalName());
+        Assert.assertEquals("DOMAIN.COM", ticket.getServerRealm());
+        Assert.assertEquals("user.test", ticket.getUserPrincipalName());
+        Assert.assertEquals("DOMAIN.COM", ticket.getUserRealm());
+    }
+
+    @Test
+    public void testAes256Ticket() throws Exception {
+        KerberosToken token = null;
+        token = new KerberosToken(aes256Token, aes256Key);
+
+        Assert.assertNotNull(token);
+        Assert.assertNotNull(token.getApRequest());
+
+        KerberosTicket ticket = token.getApRequest().getTicket();
+        Assert.assertNotNull(ticket);
+        Assert.assertEquals("HTTP/server.test.domain.com", ticket.getServerPrincipalName());
+        Assert.assertEquals("DOMAIN.COM", ticket.getServerRealm());
+        Assert.assertEquals("user.test", ticket.getUserPrincipalName());
+        Assert.assertEquals("DOMAIN.COM", ticket.getUserRealm());
+    }
+
+    @Test
+    public void testCorruptTicket() {
+        KerberosToken token = null;
+        try {
+            token = new KerberosToken(corruptToken, rc4Key);
+            Assert.fail("Should have thrown Exception.");
+        } catch(Exception e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(token);
+        }
+    }
+
+    @Test
+    public void testEmptyTicket() {
+        KerberosToken token = null;
+        try {
+            token = new KerberosToken(new byte[0], rc4Key);
+            Assert.fail("Should have thrown Exception.");
+        } catch(Exception e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(token);
+        }
+    }
+
+    @Test
+    public void testNullTicket() throws Exception {
+        KerberosToken token = null;
+        try {
+            token = new KerberosToken(null, rc4Key);
+            Assert.fail("Should have thrown NullPointerException.");
+        } catch(IOException e) {
+            e.printStackTrace();
+            Assert.fail(e.getMessage());
+        } catch(NullPointerException e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(token);
+        }
+    }
+
+    @Test
+    public void testCorruptKey() {
+        KerberosToken token = null;
+        try {
+            token = new KerberosToken(rc4Token, corruptKey);
+            Assert.fail("Should have thrown Exception.");
+        } catch(Exception e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(token);
+        }
+    }
+
+    @Test
+    public void testNoMatchingKey() {
+        KerberosToken token = null;
+        try {
+            token = new KerberosToken(rc4Token, desKey);
+            Assert.fail("Should have thrown Exception.");
+        } catch(Exception e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(token);
+        }
+    }
+
+    @Test
+    public void testKerberosPac() throws Exception {
+        KerberosToken token = new KerberosToken(rc4Token, rc4Key);
+
+        Assert.assertNotNull(token);
+        Assert.assertNotNull(token.getApRequest());
+
+        KerberosTicket ticket = token.getApRequest().getTicket();
+        Assert.assertNotNull(ticket);
+
+        AuthorizationData authzData = ticket.getAuthorizationData();
+        Assert.assertNotNull(authzData);
+        Assert.assertTrue(authzData.getElements().size() > 0);
+
+        EncryptionType eType = ticket.getTicket().getEncPart().getKey().getKeyType();
+        Pac pac = AuthzDataUtil.getPac(authzData,
+                KerberosCredentials.getServerKey(eType).getKeyData());
+        Assert.assertNotNull(pac);
+
+        PacLogonInfo logonInfo = pac.getLogonInfo();
+        Assert.assertNotNull(logonInfo);
+
+        List<String> sids = new ArrayList<String>();
+        if(logonInfo.getGroupSid() != null)
+            sids.add(logonInfo.getGroupSid().toString());
+        for(PacSid pacSid : logonInfo.getGroupSids())
+            sids.add(pacSid.toString());
+        for(PacSid pacSid : logonInfo.getExtraSids())
+            sids.add(pacSid.toString());
+        for(PacSid pacSid : logonInfo.getResourceGroupSids())
+            sids.add(pacSid.toString());
+
+        Assert.assertEquals(ticket.getUserPrincipalName(), logonInfo.getUserName());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestPac.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestPac.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestPac.java
new file mode 100644
index 0000000..37cbeca
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestPac.java
@@ -0,0 +1,135 @@
+package org.apache.kerberos.kerb.codec.test;
+
+import org.apache.kerberos.kerb.KrbException;
+import org.apache.kerberos.kerb.codec.pac.Pac;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class TestPac {
+
+    private byte[] rc4Data;
+    private byte[] desData;
+    private byte[] corruptData;
+    private byte[] rc4Key;
+    private byte[] desKey;
+    private byte[] corruptKey;
+
+    @Before
+    public void setUp() throws IOException {
+        InputStream file;
+        byte[] keyData;
+
+        file = this.getClass().getClassLoader().getResourceAsStream("rc4-pac-data");
+        rc4Data = new byte[file.available()];
+        file.read(rc4Data);
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("des-pac-data");
+        desData = new byte[file.available()];
+        file.read(desData);
+        file.close();
+
+        corruptData = new byte[]{5, 4, 2, 1, 5, 4, 2, 1, 3};
+
+        file = this.getClass().getClassLoader().getResourceAsStream("rc4-key-data");
+        keyData = new byte[file.available()];
+        file.read(keyData);
+        rc4Key = keyData;
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("des-key-data");
+        keyData = new byte[file.available()];
+        file.read(keyData);
+        desKey = keyData;
+        file.close();
+
+        corruptKey = new byte[]{5, 4, 2, 1, 5, 4, 2, 1, 3};
+    }
+
+    @Test
+    public void testRc4Pac() throws KrbException {
+        Pac pac = new Pac(rc4Data, rc4Key);
+
+        Assert.assertNotNull(pac);
+        Assert.assertNotNull(pac.getLogonInfo());
+
+        Assert.assertEquals("user.test", pac.getLogonInfo().getUserName());
+        Assert.assertEquals("User Test", pac.getLogonInfo().getUserDisplayName());
+        Assert.assertEquals(0, pac.getLogonInfo().getBadPasswordCount());
+        Assert.assertEquals(32, pac.getLogonInfo().getUserFlags());
+        Assert.assertEquals(46, pac.getLogonInfo().getLogonCount());
+        Assert.assertEquals("DOMAIN", pac.getLogonInfo().getDomainName());
+        Assert.assertEquals("WS2008", pac.getLogonInfo().getServerName());
+    }
+
+    @Test
+    public void testDesPac() throws KrbException {
+        Pac pac = new Pac(desData, desKey);
+
+        Assert.assertNotNull(pac);
+        Assert.assertNotNull(pac.getLogonInfo());
+
+        Assert.assertEquals("user.test", pac.getLogonInfo().getUserName());
+        Assert.assertEquals("User Test", pac.getLogonInfo().getUserDisplayName());
+        Assert.assertEquals(0, pac.getLogonInfo().getBadPasswordCount());
+        Assert.assertEquals(32, pac.getLogonInfo().getUserFlags());
+        Assert.assertEquals(48, pac.getLogonInfo().getLogonCount());
+        Assert.assertEquals("DOMAIN", pac.getLogonInfo().getDomainName());
+        Assert.assertEquals("WS2008", pac.getLogonInfo().getServerName());
+    }
+
+    @Test
+    public void testCorruptPac() {
+        Pac pac = null;
+        try {
+            pac = new Pac(corruptData, rc4Key);
+            Assert.fail("Should have thrown KrbException.");
+        } catch(KrbException e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(pac);
+        }
+    }
+
+    @Test
+    public void testEmptyPac() {
+        Pac pac = null;
+        try {
+            pac = new Pac(new byte[0], rc4Key);
+            Assert.fail("Should have thrown KrbException.");
+        } catch(KrbException e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(pac);
+        }
+    }
+
+    @Test
+    public void testNullPac() {
+        Pac pac = null;
+        try {
+            pac = new Pac(null, rc4Key);
+            Assert.fail("Should have thrown NullPointerException.");
+        } catch(KrbException e) {
+            e.printStackTrace();
+            Assert.fail(e.getMessage());
+        } catch(NullPointerException e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(pac);
+        }
+    }
+
+    @Test
+    public void testCorruptKey() {
+        Pac pac = null;
+        try {
+            pac = new Pac(rc4Data, corruptKey);
+            Assert.fail("Should have thrown KrbException.");
+        } catch(KrbException e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(pac);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestSpnego.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestSpnego.java b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestSpnego.java
new file mode 100644
index 0000000..46e3099
--- /dev/null
+++ b/haox-kerb/kerb-core-test/src/test/java/org/apache/kerberos/kerb/codec/test/TestSpnego.java
@@ -0,0 +1,153 @@
+package org.apache.kerberos.kerb.codec.test;
+
+import org.apache.kerberos.kerb.codec.spnego.SpnegoConstants;
+import org.apache.kerberos.kerb.codec.spnego.SpnegoInitToken;
+import org.apache.kerberos.kerb.codec.spnego.SpnegoToken;
+import org.junit.Assert;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class TestSpnego {
+
+    private byte[] rc4Token;
+    private byte[] desToken;
+    private byte[] aes128Token;
+    private byte[] aes256Token;
+    private byte[] corruptToken;
+
+    //@Before
+    public void setUp() throws IOException {
+        InputStream file;
+
+        file = this.getClass().getClassLoader().getResourceAsStream("rc4-spnego-data");
+        rc4Token = new byte[file.available()];
+        file.read(rc4Token);
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("des-spnego-data");
+        desToken = new byte[file.available()];
+        file.read(desToken);
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("aes128-spnego-data");
+        aes128Token = new byte[file.available()];
+        file.read(aes128Token);
+        file.close();
+
+        file = this.getClass().getClassLoader().getResourceAsStream("aes256-spnego-data");
+        aes256Token = new byte[file.available()];
+        file.read(aes256Token);
+        file.close();
+
+        corruptToken = new byte[]{5, 4, 2, 1};
+    }
+
+    //@Test
+    public void testRc4Token() {
+        try {
+            SpnegoToken spnegoToken = SpnegoToken.parse(rc4Token);
+
+            Assert.assertNotNull(spnegoToken);
+            Assert.assertTrue(spnegoToken instanceof SpnegoInitToken);
+            Assert.assertNotNull(spnegoToken.getMechanismToken());
+            Assert.assertTrue(spnegoToken.getMechanismToken().length < rc4Token.length);
+            Assert.assertNotNull(spnegoToken.getMechanism());
+            Assert.assertEquals(SpnegoConstants.LEGACY_KERBEROS_MECHANISM, spnegoToken.getMechanism());
+        } catch(IOException e) {
+            e.printStackTrace();
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    //@Test
+    public void testDesToken() {
+        try {
+            SpnegoToken spnegoToken = SpnegoToken.parse(desToken);
+
+            Assert.assertNotNull(spnegoToken);
+            Assert.assertTrue(spnegoToken instanceof SpnegoInitToken);
+            Assert.assertNotNull(spnegoToken.getMechanismToken());
+            Assert.assertTrue(spnegoToken.getMechanismToken().length < desToken.length);
+            Assert.assertNotNull(spnegoToken.getMechanism());
+            Assert.assertEquals(SpnegoConstants.LEGACY_KERBEROS_MECHANISM, spnegoToken.getMechanism());
+        } catch(IOException e) {
+            e.printStackTrace();
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    //@Test
+    public void testAes128Token() {
+        try {
+            SpnegoToken spnegoToken = SpnegoToken.parse(aes128Token);
+
+            Assert.assertNotNull(spnegoToken);
+            Assert.assertTrue(spnegoToken instanceof SpnegoInitToken);
+            Assert.assertNotNull(spnegoToken.getMechanismToken());
+            Assert.assertTrue(spnegoToken.getMechanismToken().length < aes128Token.length);
+            Assert.assertNotNull(spnegoToken.getMechanism());
+            Assert.assertEquals(SpnegoConstants.LEGACY_KERBEROS_MECHANISM, spnegoToken.getMechanism());
+        } catch(IOException e) {
+            e.printStackTrace();
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    //@Test
+    public void testAes256Token() {
+        try {
+            SpnegoToken spnegoToken = SpnegoToken.parse(aes256Token);
+
+            Assert.assertNotNull(spnegoToken);
+            Assert.assertTrue(spnegoToken instanceof SpnegoInitToken);
+            Assert.assertNotNull(spnegoToken.getMechanismToken());
+            Assert.assertTrue(spnegoToken.getMechanismToken().length < aes256Token.length);
+            Assert.assertNotNull(spnegoToken.getMechanism());
+            Assert.assertEquals(SpnegoConstants.LEGACY_KERBEROS_MECHANISM, spnegoToken.getMechanism());
+        } catch(IOException e) {
+            e.printStackTrace();
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    //@Test
+    public void testEmptyToken() {
+        SpnegoToken spnegoToken = null;
+        try {
+            spnegoToken = SpnegoToken.parse(new byte[0]);
+            Assert.fail("Should have thrown DecodingException.");
+        } catch(IOException e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(spnegoToken);
+        }
+    }
+
+    //@Test
+    public void testCorruptToken() {
+        SpnegoToken spnegoToken = null;
+        try {
+            spnegoToken = SpnegoToken.parse(corruptToken);
+            Assert.fail("Should have thrown DecodingException.");
+        } catch(IOException e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(spnegoToken);
+        }
+    }
+
+    //@Test
+    public void testNullToken() {
+        SpnegoToken spnegoToken = null;
+        try {
+            spnegoToken = SpnegoToken.parse(null);
+            Assert.fail("Should have thrown NullPointerException.");
+        } catch(IOException e) {
+            e.printStackTrace();
+            Assert.fail(e.getMessage());
+        } catch(NullPointerException e) {
+            Assert.assertNotNull(e);
+            Assert.assertNull(spnegoToken);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/pom.xml
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/pom.xml b/haox-kerb/kerb-core/pom.xml
new file mode 100644
index 0000000..5823424
--- /dev/null
+++ b/haox-kerb/kerb-core/pom.xml
@@ -0,0 +1,24 @@
+<?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-kerb</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>kerb-core</artifactId>
+
+    <name>Haox-kerb core</name>
+    <description>Haox-kerb core facilities</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.haox</groupId>
+            <artifactId>haox-asn1</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbConstant.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbConstant.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbConstant.java
new file mode 100644
index 0000000..6075f67
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbConstant.java
@@ -0,0 +1,7 @@
+package org.apache.kerberos.kerb;
+
+public interface KrbConstant {
+    public final static int KRB_V5 = 5;
+
+    public final static String TGS_PRINCIPAL = "krbtgt";
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbErrorCode.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbErrorCode.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbErrorCode.java
new file mode 100644
index 0000000..b7be499
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbErrorCode.java
@@ -0,0 +1,109 @@
+package org.apache.kerberos.kerb;
+
+import org.apache.kerberos.kerb.spec.KrbEnum;
+
+public enum KrbErrorCode implements KrbEnum {
+    KDC_ERR_NONE(0, "No error"),
+    KDC_ERR_NAME_EXP(1, "Client's entry in database has expired"),
+    KDC_ERR_SERVICE_EXP(2, "Server's entry in database has expired"),
+    KDC_ERR_BAD_PVNO(3, "Requested protocol version number not supported"),
+    KDC_ERR_C_OLD_MAST_KVNO(4, "Client's key encrypted in old master key"),
+    KDC_ERR_S_OLD_MAST_KVNO(5, "Server's key encrypted in old master key"),
+    KDC_ERR_C_PRINCIPAL_UNKNOWN(6, "Client not found in Kerberos database"),
+    KDC_ERR_S_PRINCIPAL_UNKNOWN(7, "Server not found in Kerberos database"),
+    KDC_ERR_PRINCIPAL_NOT_UNIQUE(8, "Multiple principal entries in database"),
+    KDC_ERR_NULL_KEY(9, "The client or server has a null key"),
+    KDC_ERR_CANNOT_POSTDATE(10, "Ticket not eligible for postdating"),
+    KDC_ERR_NEVER_VALID(11, "Requested start time is later than end time"),
+    KDC_ERR_POLICY(12, "KDC policy rejects request"),
+    KDC_ERR_BADOPTION(13, "KDC cannot accommodate requested option"),
+    KDC_ERR_ETYPE_NOSUPP(14, "KDC has no support for encryption type"),
+    KDC_ERR_SUMTYPE_NOSUPP(15, "KDC has no support for checksum type"),
+    KDC_ERR_PADATA_TYPE_NOSUPP(16, "KDC has no support for padata type"),
+    KDC_ERR_TRTYPE_NOSUPP(17, "KDC has no support for transited type"),
+    KDC_ERR_CLIENT_REVOKED(18, "Clients credentials have been revoked"),
+    KDC_ERR_SERVICE_REVOKED(19, "Credentials for server have been revoked"),
+    KDC_ERR_TGT_REVOKED(20, "TGT has been revoked"),
+    KDC_ERR_CLIENT_NOTYET(21, "Client not yet valid; try again later"),
+    KDC_ERR_SERVICE_NOTYET(22, "Server not yet valid; try again later"),
+    KDC_ERR_KEY_EXPIRED(23, "Password has expired; change password to reset"),
+    KDC_ERR_PREAUTH_FAILED(24, "Pre-authentication information was invalid"),
+    KDC_ERR_PREAUTH_REQUIRED(25, "Additional pre-authentication required"),
+    KDC_ERR_SERVER_NOMATCH(26, "Requested server and ticket don't match"),
+    KDC_ERR_MUST_USE_USER2USER(27, "Server valid for user2user only"),
+    KDC_ERR_PATH_NOT_ACCEPTED(28, "KDC Policy rejects transited path"),
+    KDC_ERR_SVC_UNAVAILABLE(29, "A service is not available"),
+    KRB_AP_ERR_BAD_INTEGRITY(31, "Integrity check on decrypted field failed"),
+    KRB_AP_ERR_TKT_EXPIRED(32, "Ticket expired"),
+    KRB_AP_ERR_TKT_NYV(33, "Ticket not yet valid"),
+    KRB_AP_ERR_REPEAT(34, "Request is a replay"),
+    KRB_AP_ERR_NOT_US(35, "The ticket isn't for us"),
+    KRB_AP_ERR_BADMATCH(36, "Ticket and authenticator don't match"),
+    KRB_AP_ERR_SKEW(37, "Clock skew too great"),
+    KRB_AP_ERR_BADADDR(38, "Incorrect net address"),
+    KRB_AP_ERR_BADVERSION(39, "Protocol version mismatch"),
+    KRB_AP_ERR_MSG_TYPE(40, "Invalid msg type"),
+    KRB_AP_ERR_MODIFIED(41, "Message stream modified"),
+    KRB_AP_ERR_BADORDER(42, "Message out of order"),
+    KRB_AP_ERR_BADKEYVER(44, "Specified version of key is not available"),
+    KRB_AP_ERR_NOKEY(45, "Service key not available"),
+    KRB_AP_ERR_MUT_FAIL(46, "Mutual authentication failed"),
+    KRB_AP_ERR_BADDIRECTION(47, "Incorrect message direction"),
+    KRB_AP_ERR_METHOD(48, "Alternative authentication method required"),
+    KRB_AP_ERR_BADSEQ(49, "Incorrect sequence number in message"),
+    KRB_AP_ERR_INAPP_CKSUM(50, "Inappropriate type of checksum in message"),
+    KRB_AP_PATH_NOT_ACCEPTED(51, "Policy rejects transited path"),
+    RESPONSE_TOO_BIG(52, "Response too big for UDP; retry with TCP"),
+    KRB_ERR_GENERIC(60, "Generic error (description in e-text)"),
+    FIELD_TOOLONG(61, "Field is too long for this implementation"),
+    KDC_ERR_CLIENT_NOT_TRUSTED(62, "Client is not trusted"),
+    KDC_NOT_TRUSTED(63, "KDC is not trusted"),
+    KDC_ERR_INVALID_SIG(64, "Signature is invalid"),
+    KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED(65, "Diffie-Hellman (DH) key parameters not accepted."),
+    CERTIFICATE_MISMATCH(66, "Certificates do not match"),
+    KRB_AP_ERR_NO_TGT(67, "No TGT available to validate USER-TO-USER"),
+    WRONG_REALM(68, "Wrong realm"),
+    KRB_AP_ERR_USER_TO_USER_REQUIRED(69, "Ticket must be for USER-TO-USER"),
+    KDC_ERR_CANT_VERIFY_CERTIFICATE(70, "Can't verify certificate"),
+    KDC_ERR_INVALID_CERTIFICATE(71, "Invalid certificate"),
+    KDC_ERR_REVOKED_CERTIFICATE(72, "Revoked certificate"),
+    KDC_ERR_REVOCATION_STATUS_UNKNOWN(73, "Revocation status unknown"),
+    REVOCATION_STATUS_UNAVAILABLE(74, "Revocation status unavailable"),
+    KDC_ERR_CLIENT_NAME_MISMATCH(75, "Client names do not match"),
+    KDC_NAME_MISMATCH(76, "KDC names do not match"),
+    KDC_ERR_INCONSISTENT_KEY_PURPOSE(77, "Inconsistent key purpose"),
+    KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED(78, "Digest in certificate not accepted"),
+    KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED(79, "PA checksum must be included"),
+    KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED(80, "Digest in signed data not accepted"),
+    KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED(81, "Public key encryption not supported"),
+
+    KRB_TIMEOUT(5000, "Network timeout");
+
+    private final int value;
+    private final String message;
+
+    private KrbErrorCode(int value, String message) {
+        this.value = value;
+        this.message = message;
+    }
+
+    public static KrbErrorCode fromValue(Integer value) {
+        if (value != null) {
+            for (KrbEnum e : values()) {
+                if (e.getValue() == value.intValue()) {
+                    return (KrbErrorCode) e;
+                }
+            }
+        }
+
+        return KRB_ERR_GENERIC;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbErrorException.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbErrorException.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbErrorException.java
new file mode 100644
index 0000000..bd6b0b4
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbErrorException.java
@@ -0,0 +1,16 @@
+package org.apache.kerberos.kerb;
+
+import org.apache.kerberos.kerb.spec.common.KrbError;
+
+public class KrbErrorException extends KrbException {
+    private KrbError krbError;
+
+    public KrbErrorException(KrbError krbError) {
+        super(krbError.getErrorCode().getMessage());
+        this.krbError = krbError;
+    }
+
+    public KrbError getKrbError() {
+        return krbError;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbException.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbException.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbException.java
new file mode 100644
index 0000000..5e50f3c
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/KrbException.java
@@ -0,0 +1,24 @@
+package org.apache.kerberos.kerb;
+
+public class KrbException extends Exception {
+
+    public KrbException(String message) {
+        super(message);
+    }
+
+    public KrbException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public KrbException(KrbErrorCode errorCode) {
+        super(errorCode.getMessage());
+    }
+
+    public KrbException(KrbErrorCode errorCode, Throwable cause) {
+        super(errorCode.getMessage(), cause);
+    }
+
+    public KrbException(KrbErrorCode errorCode, String message) {
+        super(message + " with error code: " + errorCode.name());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/codec/KrbCodec.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/codec/KrbCodec.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/codec/KrbCodec.java
new file mode 100644
index 0000000..a42a261
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/codec/KrbCodec.java
@@ -0,0 +1,74 @@
+package org.apache.kerberos.kerb.codec;
+
+import org.apache.haox.asn1.LimitedByteBuffer;
+import org.apache.haox.asn1.type.AbstractAsn1Type;
+import org.apache.haox.asn1.type.Asn1Type;
+import org.apache.kerberos.kerb.KrbException;
+import org.apache.kerberos.kerb.spec.ap.ApReq;
+import org.apache.kerberos.kerb.spec.common.KrbMessage;
+import org.apache.kerberos.kerb.spec.common.KrbMessageType;
+import org.apache.kerberos.kerb.spec.kdc.AsRep;
+import org.apache.kerberos.kerb.spec.kdc.AsReq;
+import org.apache.kerberos.kerb.spec.kdc.TgsRep;
+import org.apache.kerberos.kerb.spec.kdc.TgsReq;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class KrbCodec {
+
+    public static byte[] encode(Asn1Type krbObj) throws KrbException {
+        return krbObj.encode();
+    }
+
+    public static <T extends Asn1Type> T decode(byte[] content, Class<T> krbType) throws KrbException {
+        return decode(ByteBuffer.wrap(content), krbType);
+    }
+
+    public static <T extends Asn1Type> T decode(ByteBuffer content, Class<T> krbType) throws KrbException {
+        Asn1Type implObj = null;
+        try {
+            implObj = krbType.newInstance();
+        } catch (Exception e) {
+            throw new KrbException("Decoding failed", e);
+        }
+
+        try {
+            implObj.decode(content);
+        } catch (IOException e) {
+            throw new KrbException("Decoding failed", e);
+        }
+
+        return (T) implObj;
+    }
+
+    public static KrbMessage decodeMessage(ByteBuffer byteBuffer) throws IOException {
+        LimitedByteBuffer limitedBuffer = new LimitedByteBuffer(byteBuffer);
+        int tag = AbstractAsn1Type.readTag(limitedBuffer);
+        int tagNo = AbstractAsn1Type.readTagNo(limitedBuffer, tag);
+        int length = AbstractAsn1Type.readLength(limitedBuffer);
+        LimitedByteBuffer valueBuffer = new LimitedByteBuffer(limitedBuffer, length);
+
+        KrbMessage msg = null;
+        KrbMessageType msgType = KrbMessageType.fromValue(tagNo);
+        if (msgType == KrbMessageType.TGS_REQ) {
+            msg = new TgsReq();
+        } else if (msgType == KrbMessageType.AS_REP) {
+            msg = new AsRep();
+        } else if (msgType == KrbMessageType.AS_REQ) {
+            msg = new AsReq();
+        } else if (msgType == KrbMessageType.TGS_REP) {
+            msg = new TgsRep();
+        } else if (msgType == KrbMessageType.AP_REQ) {
+            msg = new ApReq();
+        } else if (msgType == KrbMessageType.AP_REP) {
+            msg = new ApReq();
+        } else {
+            throw new IOException("To be supported krb message type with tag: " + tag);
+        }
+        msg.decode(tag, tagNo, valueBuffer);
+
+        return msg;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosString.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosString.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosString.java
new file mode 100644
index 0000000..8a79018
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosString.java
@@ -0,0 +1,15 @@
+package org.apache.kerberos.kerb.spec;
+
+import org.apache.haox.asn1.type.Asn1GeneralString;
+
+/**
+ KerberosString  ::= GeneralString -- (IA5String)
+ */
+public class KerberosString extends Asn1GeneralString {
+    public KerberosString() {
+    }
+
+    public KerberosString(String value) {
+        super(value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosStrings.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosStrings.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosStrings.java
new file mode 100644
index 0000000..b902069
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosStrings.java
@@ -0,0 +1,24 @@
+package org.apache.kerberos.kerb.spec;
+
+import java.util.List;
+
+public class KerberosStrings extends KrbSequenceOfType<KerberosString> {
+
+    public KerberosStrings() {
+        super();
+    }
+
+    public KerberosStrings(List<String> strings) {
+        super();
+        setValues(strings);
+    }
+
+    public void setValues(List<String> values) {
+        clear();
+        if (values != null) {
+            for (String value : values) {
+                addElement(new KerberosString(value));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosTime.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosTime.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosTime.java
new file mode 100644
index 0000000..2817077
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KerberosTime.java
@@ -0,0 +1,99 @@
+package org.apache.kerberos.kerb.spec;
+
+import org.apache.haox.asn1.type.Asn1GeneralizedTime;
+
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ KerberosTime    ::= GeneralizedTime -- with no fractional seconds
+ */
+public class KerberosTime extends Asn1GeneralizedTime {
+    private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
+
+    public static final KerberosTime NEVER = new KerberosTime(Long.MAX_VALUE);
+
+    public static final int MINUTE = 60000;
+
+    public static final int DAY = MINUTE * 1440;
+
+    public static final int WEEK = MINUTE * 10080;
+
+    public KerberosTime() {
+        super(0L);
+    }
+
+    /**
+     * time in milliseconds
+     */
+    public KerberosTime(long time) {
+        super(time);
+    }
+
+    /**
+     * Return time in milliseconds
+     */
+    public long getTime() {
+        if (getValue() != null) {
+            return getValue().getTime();
+        }
+        return 0L;
+    }
+
+    /**
+     * time in milliseconds
+     */
+    public void setTime(long time) {
+        setValue(new Date(time));
+    }
+
+    public long getTimeInSeconds() {
+        return getTime() / 1000;
+    }
+
+    public boolean lessThan(KerberosTime ktime) {
+        return getValue().compareTo(ktime.getValue()) < 0;
+    }
+
+    public boolean lessThan(long time) {
+        return getValue().getTime() <= time * 1000;
+    }
+
+    public boolean greaterThan(KerberosTime ktime) {
+        return getValue().compareTo(ktime.getValue()) > 0;
+    }
+
+    /**
+     * time in milliseconds
+     */
+    public boolean isInClockSkew(long clockSkew) {
+        long delta = Math.abs(getTime() - System.currentTimeMillis());
+
+        return delta < clockSkew;
+    }
+
+    public KerberosTime copy() {
+        long time = getTime();
+        KerberosTime result = new KerberosTime(time);
+        return result;
+    }
+
+    /**
+     * time in milliseconds
+     */
+    public KerberosTime extend(long duration) {
+        long result = getTime() + duration;
+        return new KerberosTime(result);
+    }
+
+    /**
+     * Return diff time in milliseconds
+     */
+    public long diff(KerberosTime other) {
+        return getTime() - other.getTime();
+    }
+
+    public static KerberosTime now() {
+        return new KerberosTime(new Date().getTime());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbAppSequenceType.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbAppSequenceType.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbAppSequenceType.java
new file mode 100644
index 0000000..ce196af
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbAppSequenceType.java
@@ -0,0 +1,38 @@
+package org.apache.kerberos.kerb.spec;
+
+import org.apache.haox.asn1.type.Asn1FieldInfo;
+import org.apache.haox.asn1.type.TaggingSequence;
+
+/**
+ * This is for application specific sequence tagged with a number.
+ */
+public abstract class KrbAppSequenceType extends TaggingSequence {
+    public KrbAppSequenceType(int tagNo, Asn1FieldInfo[] fieldInfos) {
+        super(tagNo, fieldInfos, true);
+    }
+
+    protected int getFieldAsInt(int index) {
+        Integer value = getFieldAsInteger(index);
+        if (value != null) {
+            return value.intValue();
+        }
+        return -1;
+    }
+
+    protected void setFieldAsString(int index, String value) {
+        setFieldAs(index, new KerberosString(value));
+    }
+
+    protected KerberosTime getFieldAsTime(int index) {
+        KerberosTime value = getFieldAs(index, KerberosTime.class);
+        return value;
+    }
+
+    protected void setFieldAsTime(int index, long value) {
+        setFieldAs(index, new KerberosTime(value));
+    }
+
+    protected void setField(int index, KrbEnum krbEnum) {
+        setFieldAsInt(index, krbEnum.getValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbEnum.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbEnum.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbEnum.java
new file mode 100644
index 0000000..2457ad8
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbEnum.java
@@ -0,0 +1,5 @@
+package org.apache.kerberos.kerb.spec;
+
+public interface KrbEnum {
+    public int getValue();
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbIntegers.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbIntegers.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbIntegers.java
new file mode 100644
index 0000000..cb86a79
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbIntegers.java
@@ -0,0 +1,35 @@
+package org.apache.kerberos.kerb.spec;
+
+import org.apache.haox.asn1.type.Asn1Integer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class KrbIntegers extends KrbSequenceOfType<Asn1Integer> {
+
+    public KrbIntegers() {
+        super();
+    }
+
+    public KrbIntegers(List<Integer> values) {
+        super();
+        setValues(values);
+    }
+
+    public void setValues(List<Integer> values) {
+        clear();
+        if (values != null) {
+            for (Integer value : values) {
+                addElement(new Asn1Integer(value));
+            }
+        }
+    }
+
+    public List<Integer> getValues() {
+        List<Integer> results = new ArrayList<Integer>();
+        for (Asn1Integer value : getElements()) {
+            results.add(value.getValue());
+        }
+        return results;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbSequenceOfType.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbSequenceOfType.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbSequenceOfType.java
new file mode 100644
index 0000000..f3225da
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbSequenceOfType.java
@@ -0,0 +1,24 @@
+package org.apache.kerberos.kerb.spec;
+
+import org.apache.haox.asn1.type.Asn1SequenceOf;
+import org.apache.haox.asn1.type.Asn1String;
+import org.apache.haox.asn1.type.Asn1Type;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class KrbSequenceOfType<T extends Asn1Type> extends Asn1SequenceOf<T> {
+
+    public List<String> getAsStrings() {
+        List<T> elements = getElements();
+        List<String> results = new ArrayList<String>();
+        for (T ele : elements) {
+            if (ele instanceof Asn1String) {
+                results.add(((Asn1String) ele).getValue());
+            } else {
+                throw new RuntimeException("The targeted field type isn't of string");
+            }
+        }
+        return results;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbSequenceType.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbSequenceType.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbSequenceType.java
new file mode 100644
index 0000000..adf3828
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/KrbSequenceType.java
@@ -0,0 +1,36 @@
+package org.apache.kerberos.kerb.spec;
+
+import org.apache.haox.asn1.type.Asn1FieldInfo;
+import org.apache.haox.asn1.type.Asn1SequenceType;
+
+public abstract class KrbSequenceType extends Asn1SequenceType {
+
+    public KrbSequenceType(Asn1FieldInfo[] fieldInfos) {
+        super(fieldInfos);
+    }
+
+    protected int getFieldAsInt(int index) {
+        Integer value = getFieldAsInteger(index);
+        if (value != null) {
+            return value.intValue();
+        }
+        return -1;
+    }
+
+    protected void setFieldAsString(int index, String value) {
+        setFieldAs(index, new KerberosString(value));
+    }
+
+    protected KerberosTime getFieldAsTime(int index) {
+        KerberosTime value = getFieldAs(index, KerberosTime.class);
+        return value;
+    }
+
+    protected void setFieldAsTime(int index, long value) {
+        setFieldAs(index, new KerberosTime(value));
+    }
+
+    protected void setField(int index, KrbEnum value) {
+        setFieldAsInt(index, value.getValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApOption.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApOption.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApOption.java
new file mode 100644
index 0000000..6f9b5c2
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApOption.java
@@ -0,0 +1,39 @@
+package org.apache.kerberos.kerb.spec.ap;
+
+import org.apache.kerberos.kerb.spec.KrbEnum;
+
+/**
+ APOptions       ::= KrbFlags
+ -- reserved(0),
+ -- use-session-key(1),
+ -- mutual-required(2)
+ */
+public enum ApOption implements KrbEnum {
+    NONE(-1),
+    RESERVED(0x80000000),
+    USE_SESSION_KEY(0x40000000),
+    MUTUAL_REQUIRED(0x20000000),
+    ETYPE_NEGOTIATION(0x00000002),
+    USE_SUBKEY(0x00000001);
+
+    private final int value;
+
+    private ApOption(int value) {
+        this.value = value;
+    }
+
+    @Override
+    public int getValue() {
+        return value;
+    }
+
+    public static ApOption fromValue(int value) {
+        for (KrbEnum e : values()) {
+            if (e.getValue() == value) {
+                return (ApOption) e;
+            }
+        }
+
+        return NONE;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApOptions.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApOptions.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApOptions.java
new file mode 100644
index 0000000..b829f35
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApOptions.java
@@ -0,0 +1,14 @@
+package org.apache.kerberos.kerb.spec.ap;
+
+import org.apache.kerberos.kerb.spec.common.KrbFlags;
+
+public class ApOptions extends KrbFlags {
+
+    public ApOptions() {
+        this(0);
+    }
+
+    public ApOptions(int value) {
+        setFlags(value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApRep.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApRep.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApRep.java
new file mode 100644
index 0000000..0cdc71b
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApRep.java
@@ -0,0 +1,46 @@
+package org.apache.kerberos.kerb.spec.ap;
+
+import org.apache.haox.asn1.type.Asn1FieldInfo;
+import org.apache.haox.asn1.type.Asn1Integer;
+import org.apache.kerberos.kerb.spec.common.KrbMessage;
+import org.apache.kerberos.kerb.spec.common.EncryptedData;
+import org.apache.kerberos.kerb.spec.common.KrbMessageType;
+
+/**
+ AP-REP          ::= [APPLICATION 15] SEQUENCE {
+ pvno            [0] INTEGER (5),
+ msg-type        [1] INTEGER (15),
+ enc-part        [2] EncryptedData -- EncAPRepPart
+ }
+ */
+public class ApRep extends KrbMessage {
+    private static int ENC_PART = 2;
+
+    static Asn1FieldInfo[] fieldInfos = new Asn1FieldInfo[] {
+            new Asn1FieldInfo(PVNO, 0, Asn1Integer.class),
+            new Asn1FieldInfo(MSG_TYPE, 1, Asn1Integer.class),
+            new Asn1FieldInfo(ENC_PART, 2, EncryptedData.class)
+    };
+
+    public ApRep() {
+        super(KrbMessageType.AP_REP, fieldInfos);
+    }
+
+    private EncAPRepPart encRepPart;
+
+    public EncAPRepPart getEncRepPart() {
+        return encRepPart;
+    }
+
+    public void setEncRepPart(EncAPRepPart encRepPart) {
+        this.encRepPart = encRepPart;
+    }
+
+    public EncryptedData getEncryptedEncPart() {
+        return getFieldAs(ENC_PART, EncryptedData.class);
+    }
+
+    public void setEncryptedEncPart(EncryptedData encryptedEncPart) {
+        setFieldAs(ENC_PART, encryptedEncPart);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/23c1fd12/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApReq.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApReq.java b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApReq.java
new file mode 100644
index 0000000..7c7cba5
--- /dev/null
+++ b/haox-kerb/kerb-core/src/main/java/org/apache/kerberos/kerb/spec/ap/ApReq.java
@@ -0,0 +1,70 @@
+package org.apache.kerberos.kerb.spec.ap;
+
+import org.apache.haox.asn1.type.Asn1FieldInfo;
+import org.apache.haox.asn1.type.Asn1Integer;
+import org.apache.kerberos.kerb.spec.common.KrbMessage;
+import org.apache.kerberos.kerb.spec.common.EncryptedData;
+import org.apache.kerberos.kerb.spec.common.KrbMessageType;
+import org.apache.kerberos.kerb.spec.ticket.Ticket;
+
+/**
+ AP-REQ          ::= [APPLICATION 14] SEQUENCE {
+ pvno            [0] INTEGER (5),
+ msg-type        [1] INTEGER (14),
+ ap-options      [2] APOptions,
+ ticket          [3] Ticket,
+ authenticator   [4] EncryptedData -- Authenticator
+ }
+ */
+public class ApReq extends KrbMessage {
+    private static int AP_OPTIONS = 2;
+    private static int TICKET = 3;
+    private static int AUTHENTICATOR = 4;
+
+    static Asn1FieldInfo[] fieldInfos = new Asn1FieldInfo[] {
+            new Asn1FieldInfo(PVNO, Asn1Integer.class),
+            new Asn1FieldInfo(MSG_TYPE, Asn1Integer.class),
+            new Asn1FieldInfo(AP_OPTIONS, ApOptions.class),
+            new Asn1FieldInfo(TICKET, Ticket.class),
+            new Asn1FieldInfo(AUTHENTICATOR, EncryptedData.class)
+    };
+
+    private Authenticator authenticator;
+
+    public ApReq() {
+        super(KrbMessageType.AP_REQ, fieldInfos);
+    }
+
+    public ApOptions getApOptions() {
+        return getFieldAs(AP_OPTIONS, ApOptions.class);
+    }
+
+    public void setApOptions(ApOptions apOptions) {
+        setFieldAs(AP_OPTIONS, apOptions);
+    }
+
+    public Ticket getTicket() {
+        return getFieldAs(TICKET, Ticket.class);
+    }
+
+    public void setTicket(Ticket ticket) {
+        setFieldAs(TICKET, ticket);
+    }
+
+    public Authenticator getAuthenticator() {
+        return authenticator;
+    }
+
+    public void setAuthenticator(Authenticator authenticator) {
+        this.authenticator = authenticator;
+    }
+
+    public EncryptedData getEncryptedAuthenticator() {
+        return getFieldAs(AUTHENTICATOR, EncryptedData.class);
+    }
+
+    public void setEncryptedAuthenticator(EncryptedData encryptedAuthenticator) {
+        setFieldAs(AUTHENTICATOR, encryptedAuthenticator);
+    }
+}
+