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/12 14:06:20 UTC

[12/50] [abbrv] directory-kerberos git commit: Renaming packages in haox-kerb projects, using "apache"

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/replay/RequestRecord.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/replay/RequestRecord.java b/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/replay/RequestRecord.java
deleted file mode 100644
index 6ab6d55..0000000
--- a/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/replay/RequestRecord.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.haox.kerb.server.replay;
-
-public class RequestRecord {
-    private String clientPrincipal;
-    private String serverPrincipal;
-    private long requestTime;
-    private int microseconds;
-
-    public RequestRecord(String clientPrincipal, String serverPrincipal, long requestTime, int microseconds) {
-        this.clientPrincipal = clientPrincipal;
-        this.serverPrincipal = serverPrincipal;
-        this.requestTime = requestTime;
-        this.microseconds = microseconds;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        RequestRecord that = (RequestRecord) o;
-
-        if (microseconds != that.microseconds) return false;
-        if (requestTime != that.requestTime) return false;
-        if (!clientPrincipal.equals(that.clientPrincipal)) return false;
-        if (!serverPrincipal.equals(that.serverPrincipal)) return false;
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = clientPrincipal.hashCode();
-        result = 31 * result + serverPrincipal.hashCode();
-        result = 31 * result + (int) (requestTime ^ (requestTime >>> 32));
-        result = 31 * result + microseconds;
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/replay/SimpleCacheService.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/replay/SimpleCacheService.java b/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/replay/SimpleCacheService.java
deleted file mode 100644
index 3bddc71..0000000
--- a/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/replay/SimpleCacheService.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.haox.kerb.server.replay;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class SimpleCacheService implements CacheService {
-    private Set<RequestRecord> requests;
-
-    public SimpleCacheService() {
-        requests = new HashSet<RequestRecord>();
-    }
-
-    @Override
-    public boolean checkAndCache(RequestRecord request) {
-        if (requests.contains(request)) {
-            return true;
-        } else {
-            requests.add(request);
-        }
-        return false;
-    }
-
-    @Override
-    public void clear() {
-        requests.clear();
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/AsRequest.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/AsRequest.java b/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/AsRequest.java
deleted file mode 100644
index 875250f..0000000
--- a/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/AsRequest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.haox.kerb.server.request;
-
-import org.haox.kerb.KrbException;
-import org.haox.kerb.common.EncryptionUtil;
-import org.haox.kerb.server.KdcContext;
-import org.haox.kerb.spec.KerberosTime;
-import org.haox.kerb.spec.common.*;
-import org.haox.kerb.spec.kdc.*;
-import org.haox.kerb.spec.ticket.Ticket;
-import org.haox.kerb.spec.ticket.TicketFlag;
-
-public class AsRequest extends KdcRequest {
-
-    public AsRequest(AsReq asReq, KdcContext kdcContext) {
-        super(asReq, kdcContext);
-    }
-
-    @Override
-    protected void makeReply() throws KrbException {
-        Ticket ticket = getTicket();
-
-        AsRep reply = new AsRep();
-
-        reply.setCname(getClientEntry().getPrincipal());
-        reply.setCrealm(kdcContext.getServerRealm());
-        reply.setTicket(ticket);
-
-        EncKdcRepPart encKdcRepPart = makeEncKdcRepPart();
-        reply.setEncPart(encKdcRepPart);
-
-        EncryptionKey clientKey = getClientKey();
-        EncryptedData encryptedData = EncryptionUtil.seal(encKdcRepPart,
-                clientKey, KeyUsage.AS_REP_ENCPART);
-        reply.setEncryptedEncPart(encryptedData);
-
-        setReply(reply);
-    }
-
-    protected EncKdcRepPart makeEncKdcRepPart() {
-        KdcReq request = getKdcReq();
-        Ticket ticket = getTicket();
-
-        EncKdcRepPart encKdcRepPart = new EncAsRepPart();
-
-        //session key
-        encKdcRepPart.setKey(ticket.getEncPart().getKey());
-
-        LastReq lastReq = new LastReq();
-        LastReqEntry entry = new LastReqEntry();
-        entry.setLrType(LastReqType.THE_LAST_INITIAL);
-        entry.setLrValue(new KerberosTime());
-        lastReq.add(entry);
-        encKdcRepPart.setLastReq(lastReq);
-
-        encKdcRepPart.setNonce(request.getReqBody().getNonce());
-
-        encKdcRepPart.setFlags(ticket.getEncPart().getFlags());
-        encKdcRepPart.setAuthTime(ticket.getEncPart().getAuthTime());
-        encKdcRepPart.setStartTime(ticket.getEncPart().getStartTime());
-        encKdcRepPart.setEndTime(ticket.getEncPart().getEndTime());
-
-        if (ticket.getEncPart().getFlags().isFlagSet(TicketFlag.RENEWABLE)) {
-            encKdcRepPart.setRenewTill(ticket.getEncPart().getRenewtill());
-        }
-
-        encKdcRepPart.setSname(ticket.getSname());
-        encKdcRepPart.setSrealm(ticket.getRealm());
-        encKdcRepPart.setCaddr(ticket.getEncPart().getClientAddresses());
-
-        return encKdcRepPart;
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/KdcRequest.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/KdcRequest.java b/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/KdcRequest.java
deleted file mode 100644
index 3eefb7a..0000000
--- a/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/KdcRequest.java
+++ /dev/null
@@ -1,502 +0,0 @@
-package org.haox.kerb.server.request;
-
-import org.haox.kerb.KrbErrorCode;
-import org.haox.kerb.codec.KrbCodec;
-import org.haox.kerb.common.EncryptionUtil;
-import org.haox.kerb.crypto.EncryptionHandler;
-import org.haox.kerb.identity.KrbIdentity;
-import org.haox.kerb.server.KdcConfig;
-import org.haox.kerb.server.KdcContext;
-import org.haox.kerb.server.preauth.FastContext;
-import org.haox.kerb.server.preauth.PreauthContext;
-import org.haox.kerb.server.preauth.PreauthHandler;
-import org.haox.kerb.KrbConstant;
-import org.haox.kerb.KrbErrorException;
-import org.haox.kerb.KrbException;
-import org.haox.kerb.spec.KerberosTime;
-import org.haox.kerb.spec.common.*;
-import org.haox.kerb.spec.kdc.KdcOption;
-import org.haox.kerb.spec.kdc.KdcOptions;
-import org.haox.kerb.spec.kdc.KdcRep;
-import org.haox.kerb.spec.kdc.KdcReq;
-import org.haox.kerb.spec.pa.PaData;
-import org.haox.kerb.spec.pa.PaDataEntry;
-import org.haox.kerb.spec.pa.PaDataType;
-import org.haox.kerb.spec.ticket.EncTicketPart;
-import org.haox.kerb.spec.ticket.Ticket;
-import org.haox.kerb.spec.ticket.TicketFlag;
-import org.haox.kerb.spec.ticket.TicketFlags;
-
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.Date;
-import java.util.List;
-
-public abstract class KdcRequest {
-
-    protected KdcContext kdcContext;
-
-    private Ticket ticket;
-    private boolean isPreAuthenticated;
-    private KdcReq kdcReq;
-    private KdcRep reply;
-    private InetAddress clientAddress;
-    private boolean isTcp;
-    private EncryptionType encryptionType;
-    private EncryptionKey clientKey;
-    private KrbIdentity clientEntry;
-    private KrbIdentity serverEntry;
-    private EncryptionKey serverKey;
-    private KrbIdentity tgsEntry;
-    private PreauthContext preauthContext;
-    private FastContext fastContext;
-    private PrincipalName serverPrincipal;
-
-    public KdcRequest(KdcReq kdcReq, KdcContext kdcContext) {
-        this.kdcReq = kdcReq;
-        this.kdcContext = kdcContext;
-        this.preauthContext = kdcContext.getPreauthHandler()
-                .preparePreauthContext(this);
-        this.fastContext = new FastContext();
-    }
-
-    public KdcContext getKdcContext() {
-        return kdcContext;
-    }
-
-    public PreauthContext getPreauthContext() {
-        return preauthContext;
-    }
-
-    public void process() throws KrbException {
-        checkVersion();
-        checkClient();
-        checkServer();
-        preauth();
-        authenticate();
-        issueTicket();
-        makeReply();
-    }
-
-    public KdcReq getKdcReq() {
-        return kdcReq;
-    }
-
-    public KrbIdentity getTgsEntry() {
-        return tgsEntry;
-    }
-
-    public void setTgsEntry(KrbIdentity tgsEntry) {
-        this.tgsEntry = tgsEntry;
-    }
-
-    public boolean isTcp() {
-        return isTcp;
-    }
-
-    public void isTcp(boolean isTcp) {
-        this.isTcp = isTcp;
-    }
-
-    public KrbMessage getReply() {
-        return reply;
-    }
-
-    public void setReply(KdcRep reply) {
-        this.reply = reply;
-    }
-
-    public InetAddress getClientAddress() {
-        return clientAddress;
-    }
-
-    public void setClientAddress(InetAddress clientAddress) {
-        this.clientAddress = clientAddress;
-    }
-
-    public EncryptionType getEncryptionType() {
-        return encryptionType;
-    }
-
-    public void setEncryptionType(EncryptionType encryptionType) {
-        this.encryptionType = encryptionType;
-    }
-
-    public Ticket getTicket() {
-        return ticket;
-    }
-
-    public void setTicket(Ticket ticket) {
-        this.ticket = ticket;
-    }
-
-    public boolean isPreAuthenticated() {
-        return isPreAuthenticated;
-    }
-
-    public void setPreAuthenticated(boolean isPreAuthenticated) {
-        this.isPreAuthenticated = isPreAuthenticated;
-    }
-
-    public KrbIdentity getServerEntry() {
-        return serverEntry;
-    }
-
-    public void setServerEntry(KrbIdentity serverEntry) {
-        this.serverEntry = serverEntry;
-    }
-
-    public KrbIdentity getClientEntry() {
-        return clientEntry;
-    }
-
-    public void setClientEntry(KrbIdentity clientEntry) {
-        this.clientEntry = clientEntry;
-    }
-
-    public EncryptionKey getClientKey(EncryptionType encType) throws KrbException {
-        return getClientEntry().getKey(encType);
-    }
-
-    public EncryptionKey getClientKey() {
-        return clientKey;
-    }
-
-    public void setClientKey(EncryptionKey clientKey) {
-        this.clientKey = clientKey;
-    }
-
-    public EncryptionKey getServerKey() {
-        return serverKey;
-    }
-
-    public void setServerKey(EncryptionKey serverKey) {
-        this.serverKey = serverKey;
-    }
-
-    public PrincipalName getTgsPrincipal() {
-        PrincipalName result = new PrincipalName(kdcContext.getConfig().getTgsPrincipal());
-        result.setRealm(kdcContext.getKdcRealm());
-        return result;
-    }
-
-    protected abstract void makeReply() throws KrbException;
-
-    protected void checkVersion() throws KrbException {
-        KdcReq request = getKdcReq();
-
-        int kerberosVersion = request.getPvno();
-        if (kerberosVersion != KrbConstant.KRB_V5) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_BAD_PVNO);
-        }
-    }
-
-    protected void checkPolicy() throws KrbException {
-        KrbIdentity entry = getClientEntry();
-
-        if (entry.isDisabled()) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_CLIENT_REVOKED);
-        }
-
-        if (entry.isLocked()) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_CLIENT_REVOKED);
-        }
-
-        if (entry.getExpireTime().lessThan(new Date().getTime())) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_CLIENT_REVOKED);
-        }
-    }
-
-    protected void checkClient() throws KrbException {
-        KdcReq request = getKdcReq();
-
-        PrincipalName clientPrincipal = request.getReqBody().getCname();
-        String clientRealm = request.getReqBody().getRealm();
-        if (clientRealm == null || clientRealm.isEmpty()) {
-            clientRealm = kdcContext.getServerRealm();
-        }
-        clientPrincipal.setRealm(clientRealm);
-
-        KrbIdentity clientEntry = getEntry(clientPrincipal.getName());
-        setClientEntry(clientEntry);
-
-        EncryptionType encType = request.getReqBody().getEtypes().listIterator().next();
-        EncryptionKey clientKey = clientEntry.getKeys().get(encType);
-        setClientKey(clientKey);
-    }
-
-    protected void preauth() throws KrbException {
-        KdcReq request = getKdcReq();
-
-        PaData preAuthData = request.getPaData();
-
-        if (preauthContext.isPreauthRequired()) {
-            if (preAuthData == null || preAuthData.isEmpty()) {
-                KrbError krbError = makePreAuthenticationError(kdcContext);
-                throw new KrbErrorException(krbError);
-            } else {
-                getPreauthHandler().verify(this, preAuthData);
-            }
-        }
-
-        setPreAuthenticated(true);
-    }
-
-    protected void setPreauthRequired(boolean preauthRequired) {
-        preauthContext.setPreauthRequired(preauthRequired);
-    }
-
-    protected boolean isPreauthRequired() {
-        return preauthContext.isPreauthRequired();
-    }
-
-    protected PreauthHandler getPreauthHandler() {
-        return kdcContext.getPreauthHandler();
-    }
-
-    protected void checkEncryptionType() throws KrbException {
-        List<EncryptionType> requestedTypes = getKdcReq().getReqBody().getEtypes();
-
-        EncryptionType bestType = EncryptionUtil.getBestEncryptionType(requestedTypes,
-                kdcContext.getConfig().getEncryptionTypes());
-
-        if (bestType == null) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_ETYPE_NOSUPP);
-        }
-
-        setEncryptionType(bestType);
-    }
-
-    protected void authenticate() throws KrbException {
-        checkEncryptionType();
-        checkPolicy();
-    }
-
-    protected void issueTicket() throws KrbException {
-        KdcReq request = getKdcReq();
-
-        EncryptionType encryptionType = getEncryptionType();
-        EncryptionKey serverKey = getServerEntry().getKeys().get(encryptionType);
-
-        PrincipalName ticketPrincipal = request.getReqBody().getSname();
-
-        EncTicketPart encTicketPart = new EncTicketPart();
-        KdcConfig config = kdcContext.getConfig();
-
-        TicketFlags ticketFlags = new TicketFlags();
-        encTicketPart.setFlags(ticketFlags);
-        ticketFlags.setFlag(TicketFlag.INITIAL);
-
-        if (isPreAuthenticated()) {
-            ticketFlags.setFlag(TicketFlag.PRE_AUTH);
-        }
-
-        if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.FORWARDABLE)) {
-            if (!config.isForwardableAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-
-            ticketFlags.setFlag(TicketFlag.FORWARDABLE);
-        }
-
-        if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.PROXIABLE)) {
-            if (!config.isProxiableAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-
-            ticketFlags.setFlag(TicketFlag.PROXIABLE);
-        }
-
-        if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.ALLOW_POSTDATE)) {
-            if (!config.isPostdatedAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-
-            ticketFlags.setFlag(TicketFlag.MAY_POSTDATE);
-        }
-
-        KdcOptions kdcOptions = request.getReqBody().getKdcOptions();
-
-        EncryptionKey sessionKey = EncryptionHandler.random2Key(getEncryptionType());
-        encTicketPart.setKey(sessionKey);
-
-        encTicketPart.setCname(request.getReqBody().getCname());
-        encTicketPart.setCrealm(request.getReqBody().getRealm());
-
-        TransitedEncoding transEnc = new TransitedEncoding();
-        encTicketPart.setTransited(transEnc);
-        String serverRealm = request.getReqBody().getRealm();
-
-        KerberosTime now = KerberosTime.now();
-        encTicketPart.setAuthTime(now);
-
-        KerberosTime krbStartTime = request.getReqBody().getFrom();
-        if (krbStartTime == null || krbStartTime.lessThan(now) ||
-                krbStartTime.isInClockSkew(config.getAllowableClockSkew())) {
-            krbStartTime = now;
-        }
-        if (krbStartTime.greaterThan(now)
-                && !krbStartTime.isInClockSkew(config.getAllowableClockSkew())
-                && !kdcOptions.isFlagSet(KdcOption.POSTDATED)) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_CANNOT_POSTDATE);
-        }
-
-        if (kdcOptions.isFlagSet(KdcOption.POSTDATED)) {
-            if (!config.isPostdatedAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-
-            ticketFlags.setFlag(TicketFlag.POSTDATED);
-            encTicketPart.setStartTime(krbStartTime);
-        }
-
-        KerberosTime krbEndTime = request.getReqBody().getTill();
-        if (krbEndTime == null) {
-            krbEndTime = krbStartTime.extend(config.getMaximumTicketLifetime() * 1000);
-        } else if (krbStartTime.greaterThan(krbEndTime)) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_NEVER_VALID);
-        }
-        encTicketPart.setEndTime(krbEndTime);
-
-        long ticketLifeTime = Math.abs(krbEndTime.diff(krbStartTime));
-        if (ticketLifeTime < config.getMinimumTicketLifetime()) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_NEVER_VALID);
-        }
-
-        KerberosTime krbRtime = request.getReqBody().getRtime();
-        if (kdcOptions.isFlagSet(KdcOption.RENEWABLE_OK)) {
-            kdcOptions.setFlag(KdcOption.RENEWABLE);
-        }
-        if (kdcOptions.isFlagSet(KdcOption.RENEWABLE)) {
-            if (!config.isRenewableAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-
-            ticketFlags.setFlag(TicketFlag.RENEWABLE);
-
-            if (krbRtime == null) {
-                krbRtime = KerberosTime.NEVER;
-            }
-            KerberosTime allowedMaximumRenewableTime = krbStartTime;
-            allowedMaximumRenewableTime.extend(config.getMaximumRenewableLifetime() * 1000);
-            if (krbRtime.greaterThan(allowedMaximumRenewableTime)) {
-                krbRtime = allowedMaximumRenewableTime;
-            }
-            encTicketPart.setRenewtill(krbRtime);
-        }
-
-        HostAddresses hostAddresses = request.getReqBody().getAddresses();
-        if (hostAddresses == null || hostAddresses.isEmpty()) {
-            if (!config.isEmptyAddressesAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-        } else {
-            encTicketPart.setClientAddresses(hostAddresses);
-        }
-
-        EncryptedData encryptedData = EncryptionUtil.seal(encTicketPart,
-                serverKey, KeyUsage.KDC_REP_TICKET);
-
-        Ticket newTicket = new Ticket();
-        newTicket.setSname(ticketPrincipal);
-        newTicket.setEncryptedEncPart(encryptedData);
-        newTicket.setRealm(serverRealm);
-        newTicket.setEncPart(encTicketPart);
-
-        setTicket(newTicket);
-    }
-
-    private void checkServer() throws KrbException {
-        KdcReq request = getKdcReq();
-
-        KrbIdentity tgsEntry = getEntry(getTgsPrincipal().getName());
-        setTgsEntry(tgsEntry);
-
-        PrincipalName principal = request.getReqBody().getSname();
-        String serverRealm = request.getReqBody().getRealm();
-        if (serverRealm == null || serverRealm.isEmpty()) {
-            serverRealm = kdcContext.getServerRealm();
-        }
-        principal.setRealm(serverRealm);
-
-        KrbIdentity serverEntry = getEntry(principal.getName());
-        setServerEntry(serverEntry);
-
-        EncryptionType encType = request.getReqBody().getEtypes().listIterator().next();
-        EncryptionKey serverKey = serverEntry.getKeys().get(encType);
-        setServerKey(serverKey);
-    }
-
-    protected KrbError makePreAuthenticationError(KdcContext kdcContext) throws KrbException {
-        EncryptionType requestedType = getEncryptionType();
-        List<EncryptionType> encryptionTypes = kdcContext.getConfig().getEncryptionTypes();
-        boolean isNewEtype = true;
-
-        EtypeInfo2 eTypeInfo2 = new EtypeInfo2();
-
-        EtypeInfo eTypeInfo = new EtypeInfo();
-
-        for (EncryptionType encryptionType : encryptionTypes) {
-            if (!isNewEtype) {
-                EtypeInfoEntry etypeInfoEntry = new EtypeInfoEntry();
-                etypeInfoEntry.setEtype(encryptionType);
-                etypeInfoEntry.setSalt(null);
-                eTypeInfo.add(etypeInfoEntry);
-            }
-
-            EtypeInfo2Entry etypeInfo2Entry = new EtypeInfo2Entry();
-            etypeInfo2Entry.setEtype(encryptionType);
-            eTypeInfo2.add(etypeInfo2Entry);
-        }
-
-        byte[] encTypeInfo = null;
-        byte[] encTypeInfo2 = null;
-        if (!isNewEtype) {
-            encTypeInfo = KrbCodec.encode(eTypeInfo);
-        }
-        encTypeInfo2 = KrbCodec.encode(eTypeInfo2);
-
-        MethodData methodData = new MethodData();
-        methodData.add(new PaDataEntry(PaDataType.ENC_TIMESTAMP, null));
-        if (!isNewEtype) {
-            methodData.add(new PaDataEntry(PaDataType.ETYPE_INFO, encTypeInfo));
-        }
-        methodData.add(new PaDataEntry(PaDataType.ETYPE_INFO2, encTypeInfo2));
-
-        KrbError krbError = new KrbError();
-        krbError.setErrorCode(KrbErrorCode.KDC_ERR_PREAUTH_REQUIRED);
-        byte[] encodedData = KrbCodec.encode(methodData);
-        krbError.setEdata(encodedData);
-
-        return krbError;
-    }
-
-    protected KrbIdentity getEntry(String principal) throws KrbException {
-        KrbIdentity entry = null;
-        KrbErrorCode krbErrorCode = KrbErrorCode.KDC_ERR_C_PRINCIPAL_UNKNOWN;
-
-        try {
-            entry = kdcContext.getIdentityService().getIdentity(principal);
-        } catch (Exception e) {
-            throw new KrbException(krbErrorCode, e);
-        }
-
-        if (entry == null) {
-            throw new KrbException(krbErrorCode);
-        }
-
-        return entry;
-    }
-
-    public ByteBuffer getRequestBody() throws KrbException {
-        return null;
-    }
-
-    public EncryptionKey getArmorKey() throws KrbException {
-        return fastContext.armorKey;
-    }
-
-    public PrincipalName getServerPrincipal() {
-        return serverPrincipal;
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/TgsRequest.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/TgsRequest.java b/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/TgsRequest.java
deleted file mode 100644
index 2e36268..0000000
--- a/haox-kerb/kerb-server/src/main/java/org/haox/kerb/server/request/TgsRequest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package org.haox.kerb.server.request;
-
-import org.haox.kerb.KrbErrorCode;
-import org.haox.kerb.codec.KrbCodec;
-import org.haox.kerb.common.EncryptionUtil;
-import org.haox.kerb.server.KdcContext;
-import org.haox.kerb.KrbConstant;
-import org.haox.kerb.KrbException;
-import org.haox.kerb.spec.KerberosTime;
-import org.haox.kerb.spec.ap.ApOption;
-import org.haox.kerb.spec.ap.ApReq;
-import org.haox.kerb.spec.ap.Authenticator;
-import org.haox.kerb.spec.common.*;
-import org.haox.kerb.spec.kdc.*;
-import org.haox.kerb.spec.pa.PaDataEntry;
-import org.haox.kerb.spec.ticket.EncTicketPart;
-import org.haox.kerb.spec.ticket.Ticket;
-import org.haox.kerb.spec.ticket.TicketFlag;
-
-import java.nio.ByteBuffer;
-
-public class TgsRequest extends KdcRequest {
-
-    private EncryptionKey tgtSessionKey;
-
-    public TgsRequest(TgsReq tgsReq, KdcContext kdcContext) {
-        super(tgsReq, kdcContext);
-
-        setPreauthRequired(true);
-    }
-
-    public EncryptionKey getTgtSessionKey() {
-        return tgtSessionKey;
-    }
-
-    public void setTgtSessionKey(EncryptionKey tgtSessionKey) {
-        this.tgtSessionKey = tgtSessionKey;
-    }
-
-    public void verifyAuthenticator(PaDataEntry paDataEntry) throws KrbException {
-        ApReq apReq = KrbCodec.decode(paDataEntry.getPaDataValue(), ApReq.class);
-
-        if (apReq.getPvno() != KrbConstant.KRB_V5) {
-            throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADVERSION);
-        }
-
-        if (apReq.getMsgType() != KrbMessageType.AP_REQ) {
-            throw new KrbException(KrbErrorCode.KRB_AP_ERR_MSG_TYPE);
-        }
-
-        EncryptionType encType = getKdcReq().getReqBody().getEtypes().listIterator().next();
-        EncryptionKey tgsKey = getTgsEntry().getKeys().get(encType);
-
-        Ticket ticket = apReq.getTicket();
-        if (ticket.getTktvno() != KrbConstant.KRB_V5) {
-            throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADVERSION);
-        }
-
-        EncTicketPart encPart = EncryptionUtil.unseal(ticket.getEncryptedEncPart(),
-                tgsKey, KeyUsage.KDC_REP_TICKET, EncTicketPart.class);
-        ticket.setEncPart(encPart);
-
-        EncryptionKey encKey = null;
-        //if (apReq.getApOptions().isFlagSet(ApOptions.USE_SESSION_KEY)) {
-        encKey = ticket.getEncPart().getKey();
-
-        if (encKey == null) {
-            throw new KrbException(KrbErrorCode.KRB_AP_ERR_NOKEY);
-        }
-        Authenticator authenticator = EncryptionUtil.unseal(apReq.getEncryptedAuthenticator(),
-                encKey, KeyUsage.TGS_REQ_AUTH, Authenticator.class);
-
-        if (!authenticator.getCname().equals(ticket.getEncPart().getCname())) {
-            throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADMATCH);
-        }
-
-        HostAddresses hostAddresses = ticket.getEncPart().getClientAddresses();
-        if (hostAddresses == null || hostAddresses.isEmpty()) {
-            if (!kdcContext.getConfig().isEmptyAddressesAllowed()) {
-                throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADADDR);
-            }
-        } else if (!hostAddresses.contains(getClientAddress())) {
-            throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADADDR);
-        }
-
-        PrincipalName serverPrincipal = ticket.getSname();
-        serverPrincipal.setRealm(ticket.getRealm());
-        PrincipalName clientPrincipal = authenticator.getCname();
-        clientPrincipal.setRealm(authenticator.getCrealm());
-
-        if (!authenticator.getCtime().isInClockSkew(
-                kdcContext.getConfig().getAllowableClockSkew() * 1000)) {
-            throw new KrbException(KrbErrorCode.KRB_AP_ERR_SKEW);
-        }
-
-        KerberosTime now = KerberosTime.now();
-        KerberosTime startTime = ticket.getEncPart().getStartTime();
-        if (startTime == null) {
-            startTime = ticket.getEncPart().getAuthTime();
-        }
-        if (! startTime.lessThan(now)) {
-            throw new KrbException(KrbErrorCode.KRB_AP_ERR_TKT_NYV);
-        }
-
-        KerberosTime endTime = ticket.getEncPart().getEndTime();
-        if (! endTime.greaterThan(now)) {
-            throw new KrbException(KrbErrorCode.KRB_AP_ERR_TKT_EXPIRED);
-        }
-
-        apReq.getApOptions().setFlag(ApOption.MUTUAL_REQUIRED);
-
-        setTgtSessionKey(ticket.getEncPart().getKey());
-    }
-
-    @Override
-    protected void makeReply() throws KrbException {
-        Ticket ticket = getTicket();
-
-        TgsRep reply = new TgsRep();
-
-        reply.setCname(getClientEntry().getPrincipal());
-        reply.setCrealm(kdcContext.getServerRealm());
-        reply.setTicket(ticket);
-
-        EncKdcRepPart encKdcRepPart = makeEncKdcRepPart();
-        reply.setEncPart(encKdcRepPart);
-
-        EncryptionKey sessionKey = getTgtSessionKey();
-        EncryptedData encryptedData = EncryptionUtil.seal(encKdcRepPart,
-                sessionKey, KeyUsage.TGS_REP_ENCPART_SESSKEY);
-        reply.setEncryptedEncPart(encryptedData);
-
-        setReply(reply);
-    }
-
-    private EncKdcRepPart makeEncKdcRepPart() {
-        KdcReq request = getKdcReq();
-        Ticket ticket = getTicket();
-
-        EncKdcRepPart encKdcRepPart = new EncTgsRepPart();
-
-        //session key
-        encKdcRepPart.setKey(ticket.getEncPart().getKey());
-
-        LastReq lastReq = new LastReq();
-        LastReqEntry entry = new LastReqEntry();
-        entry.setLrType(LastReqType.THE_LAST_INITIAL);
-        entry.setLrValue(new KerberosTime());
-        lastReq.add(entry);
-        encKdcRepPart.setLastReq(lastReq);
-
-        encKdcRepPart.setNonce(request.getReqBody().getNonce());
-
-        encKdcRepPart.setFlags(ticket.getEncPart().getFlags());
-        encKdcRepPart.setAuthTime(ticket.getEncPart().getAuthTime());
-        encKdcRepPart.setStartTime(ticket.getEncPart().getStartTime());
-        encKdcRepPart.setEndTime(ticket.getEncPart().getEndTime());
-
-        if (ticket.getEncPart().getFlags().isFlagSet(TicketFlag.RENEWABLE)) {
-            encKdcRepPart.setRenewTill(ticket.getEncPart().getRenewtill());
-        }
-
-        encKdcRepPart.setSname(ticket.getSname());
-        encKdcRepPart.setSrealm(ticket.getRealm());
-        encKdcRepPart.setCaddr(ticket.getEncPart().getClientAddresses());
-
-        return encKdcRepPart;
-    }
-
-    public ByteBuffer getRequestBody() throws KrbException {
-        return null;
-    }
-
-    public EncryptionKey getArmorKey() throws KrbException {
-        return null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-server/src/test/java/org/apache/kerberos/kerb/server/KdcTest.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-server/src/test/java/org/apache/kerberos/kerb/server/KdcTest.java b/haox-kerb/kerb-server/src/test/java/org/apache/kerberos/kerb/server/KdcTest.java
new file mode 100644
index 0000000..9c01008
--- /dev/null
+++ b/haox-kerb/kerb-server/src/test/java/org/apache/kerberos/kerb/server/KdcTest.java
@@ -0,0 +1,51 @@
+package org.apache.kerberos.kerb.server;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+
+public class KdcTest {
+
+    private String serverHost = "localhost";
+    private short serverPort = 8088;
+
+    private SimpleKdcServer kdcServer;
+
+    @Before
+    public void setUp() throws Exception {
+        kdcServer = new SimpleKdcServer();
+        kdcServer.setKdcHost(serverHost);
+        kdcServer.setKdcPort(serverPort);
+        kdcServer.init();
+        kdcServer.start();
+    }
+
+    @Test
+    public void testKdc() throws IOException, InterruptedException {
+        Thread.sleep(10);
+
+        SocketChannel socketChannel = SocketChannel.open();
+        socketChannel.configureBlocking(true);
+        SocketAddress sa = new InetSocketAddress(serverHost, serverPort);
+        socketChannel.connect(sa);
+
+        String BAD_KRB_MESSAGE = "Hello World!";
+        ByteBuffer writeBuffer = ByteBuffer.allocate(4 + BAD_KRB_MESSAGE.getBytes().length);
+        writeBuffer.putInt(BAD_KRB_MESSAGE.getBytes().length);
+        writeBuffer.put(BAD_KRB_MESSAGE.getBytes());
+        writeBuffer.flip();
+
+        socketChannel.write(writeBuffer);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        kdcServer.stop();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-server/src/test/java/org/haox/kerb/server/KdcTest.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-server/src/test/java/org/haox/kerb/server/KdcTest.java b/haox-kerb/kerb-server/src/test/java/org/haox/kerb/server/KdcTest.java
deleted file mode 100644
index 05a3f6e..0000000
--- a/haox-kerb/kerb-server/src/test/java/org/haox/kerb/server/KdcTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.haox.kerb.server;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
-
-public class KdcTest {
-
-    private String serverHost = "localhost";
-    private short serverPort = 8088;
-
-    private SimpleKdcServer kdcServer;
-
-    @Before
-    public void setUp() throws Exception {
-        kdcServer = new SimpleKdcServer();
-        kdcServer.setKdcHost(serverHost);
-        kdcServer.setKdcPort(serverPort);
-        kdcServer.init();
-        kdcServer.start();
-    }
-
-    @Test
-    public void testKdc() throws IOException, InterruptedException {
-        Thread.sleep(10);
-
-        SocketChannel socketChannel = SocketChannel.open();
-        socketChannel.configureBlocking(true);
-        SocketAddress sa = new InetSocketAddress(serverHost, serverPort);
-        socketChannel.connect(sa);
-
-        String BAD_KRB_MESSAGE = "Hello World!";
-        ByteBuffer writeBuffer = ByteBuffer.allocate(4 + BAD_KRB_MESSAGE.getBytes().length);
-        writeBuffer.putInt(BAD_KRB_MESSAGE.getBytes().length);
-        writeBuffer.put(BAD_KRB_MESSAGE.getBytes());
-        writeBuffer.flip();
-
-        socketChannel.write(writeBuffer);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        kdcServer.stop();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-server/src/test/resources/kdc-krb5.conf
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-server/src/test/resources/kdc-krb5.conf b/haox-kerb/kerb-server/src/test/resources/kdc-krb5.conf
deleted file mode 100644
index d118dd1..0000000
--- a/haox-kerb/kerb-server/src/test/resources/kdc-krb5.conf
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-#
-[libdefaults]
-    default_realm = {0}
-    udp_preference_limit = 1
-
-[realms]
-    {0} = '{'
-        kdc = {1}:{2}
-    '}'
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-server/src/test/resources/kdc.ldiff
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-server/src/test/resources/kdc.ldiff b/haox-kerb/kerb-server/src/test/resources/kdc.ldiff
deleted file mode 100644
index e344131..0000000
--- a/haox-kerb/kerb-server/src/test/resources/kdc.ldiff
+++ /dev/null
@@ -1,30 +0,0 @@
-dn: ou=users,dc=${0},dc=${1}
-objectClass: organizationalUnit
-objectClass: top
-ou: users
-
-dn: uid=krbtgt,ou=users,dc=${0},dc=${1}
-objectClass: top
-objectClass: person
-objectClass: inetOrgPerson
-objectClass: krb5principal
-objectClass: krb5kdcentry
-cn: KDC Service
-sn: Service
-uid: krbtgt
-userPassword: secret
-krb5PrincipalName: krbtgt/${2}.${3}@${2}.${3}
-krb5KeyVersionNumber: 0
-
-dn: uid=ldap,ou=users,dc=${0},dc=${1}
-objectClass: top
-objectClass: person
-objectClass: inetOrgPerson
-objectClass: krb5principal
-objectClass: krb5kdcentry
-cn: LDAP
-sn: Service
-uid: ldap
-userPassword: secret
-krb5PrincipalName: ldap/${4}@${2}.${3}
-krb5KeyVersionNumber: 0
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/KrbInputStream.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/KrbInputStream.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/KrbInputStream.java
new file mode 100644
index 0000000..a011d8e
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/KrbInputStream.java
@@ -0,0 +1,55 @@
+package org.apache.kerberos.kerb;
+
+import org.apache.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerberos.kerb.spec.common.EncryptionType;
+import org.apache.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public abstract class KrbInputStream extends DataInputStream
+{
+    public KrbInputStream(InputStream in) {
+        super(in);
+    }
+
+    public KerberosTime readTime() throws IOException {
+        long value = readInt();
+        KerberosTime time = new KerberosTime(value * 1000);
+        return time;
+    }
+
+    public abstract PrincipalName readPrincipal(int version) throws IOException;
+
+    public EncryptionKey readKey(int version) throws IOException {
+        int eType = readShort();
+        EncryptionType encryptionType = EncryptionType.fromValue(eType);
+
+        byte[] keyData = readCountedOctets();
+        EncryptionKey key = new EncryptionKey(encryptionType, keyData);
+
+        return key;
+    }
+
+    public String readCountedString() throws IOException {
+        byte[] countedOctets = readCountedOctets();
+        // ASCII
+        return new String(countedOctets);
+    }
+
+    public byte[] readCountedOctets() throws IOException {
+        int len = readOctetsCount();
+        if (len == 0) {
+            return null;
+        }
+
+        byte[] data = new byte[len];
+        read(data);
+
+        return data;
+    }
+
+    public abstract int readOctetsCount() throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/KrbOutputStream.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/KrbOutputStream.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/KrbOutputStream.java
new file mode 100644
index 0000000..e97395f
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/KrbOutputStream.java
@@ -0,0 +1,47 @@
+package org.apache.kerberos.kerb;
+
+import org.apache.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public abstract class KrbOutputStream extends DataOutputStream
+{
+	public KrbOutputStream(OutputStream out) {
+        super(out);
+    }
+
+    public abstract void writePrincipal(PrincipalName principal, int version) throws IOException;
+
+    public void writeRealm(String realm) throws IOException {
+        writeCountedString(realm);
+    }
+
+    public abstract void writeKey(EncryptionKey key, int version) throws IOException;
+
+    public void writeTime(KerberosTime ktime) throws IOException {
+    	int time = 0;
+    	if (ktime != null) {
+    		time = (int) (ktime.getValue().getTime() / 1000);
+    	}
+    	writeInt(time);
+    }
+
+    public void writeCountedString(String string) throws IOException {
+        byte[] data = string != null ? string.getBytes() : null; // ASCII
+
+        writeCountedOctets(data);
+    }
+
+    public void writeCountedOctets(byte[] data) throws IOException {
+        if (data != null) {
+            writeInt(data.length);
+            write(data);
+        } else {
+            writeInt(0);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredCacheInputStream.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredCacheInputStream.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredCacheInputStream.java
new file mode 100644
index 0000000..da5aeba
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredCacheInputStream.java
@@ -0,0 +1,148 @@
+package org.apache.kerberos.kerb.ccache;
+
+import org.apache.kerberos.kerb.KrbInputStream;
+import org.apache.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerberos.kerb.spec.common.*;
+import org.apache.kerberos.kerb.spec.ticket.Ticket;
+import org.apache.kerberos.kerb.spec.ticket.TicketFlags;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CredCacheInputStream extends KrbInputStream
+{
+    public CredCacheInputStream(InputStream in) {
+        super(in);
+    }
+
+    @Override
+    public PrincipalName readPrincipal(int version) throws IOException {
+        NameType nameType = NameType.NT_UNKNOWN;
+        if (version != CredentialCache.FCC_FVNO_1) {
+            int typeValue = readInt();
+            nameType = NameType.fromValue(typeValue);
+        }
+
+        int numComponents = readInt();
+        if (version == CredentialCache.FCC_FVNO_1) {
+            numComponents -= 1;
+        }
+
+        String realm = readCountedString();
+
+        List<String> nameStrings = new ArrayList<String>();
+        String component;
+        for (int i = 0; i < numComponents; i++) { // sub 1 if version 0x501
+            component = readCountedString();
+            nameStrings.add(component);
+        }
+
+        PrincipalName principal = new PrincipalName(nameStrings, nameType);
+        principal.setRealm(realm);
+
+        return principal;
+    }
+
+    public EncryptionKey readKey(int version) throws IOException {
+        if (version == CredentialCache.FCC_FVNO_3) {
+            readShort(); //  ignore keytype
+        }
+
+        return super.readKey(version);
+    }
+
+    public KerberosTime[] readTimes() throws IOException {
+        KerberosTime[] times = new KerberosTime[4];
+
+        for (int i = 0; i < times.length; ++i) {
+            times[i] = readTime();
+        }
+
+        return times;
+    }
+
+    public boolean readIsSkey() throws IOException {
+        int value = readByte();
+        return value == 1 ? true : false;
+    }
+
+    public HostAddresses readAddr() throws IOException {
+        int numAddresses = readInt();
+        if (numAddresses <= 0) {
+            return null;
+        }
+
+        HostAddress[] addresses = new HostAddress[numAddresses];
+        for (int i = 0; i < numAddresses; i++) {
+            addresses[i] = readAddress();
+        }
+
+        HostAddresses result = new HostAddresses();
+        result.addElements(addresses);
+        return result;
+    }
+
+    public HostAddress readAddress() throws IOException {
+        int typeValue = readShort();
+        HostAddrType addrType = HostAddrType.fromValue(typeValue);
+        byte[] addrData = readCountedOctets();
+
+        HostAddress addr = new HostAddress();
+        addr.setAddrType(addrType);
+        addr.setAddress(addrData);
+
+        return addr;
+    }
+
+    public AuthorizationData readAuthzData() throws IOException {
+        int numEntries = readInt();
+        if (numEntries <= 0) {
+            return null;
+        }
+
+        AuthorizationDataEntry[] authzData = new AuthorizationDataEntry[numEntries];
+        for (int i = 0; i < numEntries; i++) {
+            authzData[i] = readAuthzDataEntry();
+        }
+
+        AuthorizationData result = new AuthorizationData();
+        result.addElements(authzData);
+        return result;
+    }
+
+    public AuthorizationDataEntry readAuthzDataEntry() throws IOException {
+        int typeValue = readShort();
+        AuthorizationType authzType = AuthorizationType.fromValue(typeValue);
+        byte[] authzData = readCountedOctets();
+
+        AuthorizationDataEntry authzEntry = new AuthorizationDataEntry();
+        authzEntry.setAuthzType(authzType);
+        authzEntry.setAuthzData(authzData);
+
+        return authzEntry;
+    }
+
+    @Override
+    public int readOctetsCount() throws IOException {
+        return readInt();
+    }
+
+    public TicketFlags readTicketFlags() throws IOException {
+        int flags = readInt();
+        TicketFlags tktFlags = new TicketFlags(flags);
+        return tktFlags;
+    }
+
+    public Ticket readTicket() throws IOException {
+        byte[] ticketData = readCountedOctets();
+        if (ticketData == null) {
+            return null;
+        }
+
+        Ticket ticket = new Ticket();
+        ticket.decode(ticketData);
+        return ticket;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredCacheOutputStream.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredCacheOutputStream.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredCacheOutputStream.java
new file mode 100644
index 0000000..04884e0
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredCacheOutputStream.java
@@ -0,0 +1,104 @@
+package org.apache.kerberos.kerb.ccache;
+
+import org.apache.kerberos.kerb.KrbOutputStream;
+import org.apache.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerberos.kerb.spec.common.*;
+import org.apache.kerberos.kerb.spec.ticket.Ticket;
+import org.apache.kerberos.kerb.spec.ticket.TicketFlags;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+public class CredCacheOutputStream extends KrbOutputStream
+{
+	public CredCacheOutputStream(OutputStream out) {
+        super(out);
+    }
+
+    @Override
+    public void writePrincipal(PrincipalName principal, int version) throws IOException {
+        List<String> nameComponents = principal.getNameStrings();
+
+    	if (version != CredentialCache.FCC_FVNO_1) {
+        	writeInt(principal.getNameType().getValue());
+        }
+
+        int numComponents = nameComponents.size();
+        if (version == CredentialCache.FCC_FVNO_1) {
+            numComponents ++;
+        }
+        writeInt(numComponents);
+        
+        writeRealm(principal.getRealm());
+        
+        for (String nameCom : nameComponents) {
+            writeCountedString(nameCom);
+        }
+    }
+
+    @Override
+    public void writeKey(EncryptionKey key, int version) throws IOException {
+    	writeShort(key.getKeyType().getValue());
+    	if (version == CredentialCache.FCC_FVNO_3) {
+    		writeShort(key.getKeyType().getValue());
+    	}
+
+        writeCountedOctets(key.getKeyData());
+    }
+
+    public void writeTimes(KerberosTime[] times) throws IOException {
+        for (int i = 0; i < times.length; ++i) {
+            writeTime(times[i]);
+        }
+    }
+
+    public void writeAddresses(HostAddresses addrs) throws IOException {
+    	if (addrs == null) {
+    		writeInt(0);
+    	} else {
+            List<HostAddress> addresses = addrs.getElements();
+    		write(addresses.size());
+    		for (HostAddress addr : addresses) {
+                writeAddress(addr);
+    		}
+    	}
+    }
+
+    public void writeAddress(HostAddress address) throws IOException {
+        write(address.getAddrType().getValue());
+        write(address.getAddress().length);
+        write(address.getAddress(), 0,
+                address.getAddress().length);
+    }
+
+    public void writeAuthzData(AuthorizationData authData) throws IOException  {
+    	if (authData == null) {
+    		writeInt(0);
+    	} else {
+    		for (AuthorizationDataEntry entry : authData.getElements()) {
+    			write(entry.getAuthzType().getValue());
+    			write(entry.getAuthzData().length);
+    			write(entry.getAuthzData());
+    		}
+    	}
+    }
+    
+    public void writeTicket(Ticket t) throws IOException  {
+        if (t == null) {
+            writeInt(0);
+        } else {
+            byte[] bytes = t.encode();
+            writeInt(bytes.length);
+            write(bytes);
+        }
+    }
+
+    public void writeIsSkey(boolean isEncInSKey) throws IOException {
+        writeByte(isEncInSKey ? 1 : 0);
+    }
+
+    public void writeTicketFlags(TicketFlags ticketFlags) throws IOException {
+        writeInt(ticketFlags.getFlags());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/Credential.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/Credential.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/Credential.java
new file mode 100644
index 0000000..59e9ad5
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/Credential.java
@@ -0,0 +1,206 @@
+package org.apache.kerberos.kerb.ccache;
+
+import org.apache.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerberos.kerb.spec.common.AuthorizationData;
+import org.apache.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerberos.kerb.spec.common.HostAddresses;
+import org.apache.kerberos.kerb.spec.common.PrincipalName;
+import org.apache.kerberos.kerb.spec.kdc.EncKdcRepPart;
+import org.apache.kerberos.kerb.spec.ticket.AbstractServiceTicket;
+import org.apache.kerberos.kerb.spec.ticket.TgtTicket;
+import org.apache.kerberos.kerb.spec.ticket.Ticket;
+import org.apache.kerberos.kerb.spec.ticket.TicketFlags;
+
+import java.io.IOException;
+
+public class Credential
+{
+    private static String CONF_REALM = "X-CACHECONF:";
+
+    private PrincipalName clientName;
+    private String clientRealm;
+    private PrincipalName serverName;
+    private String serverRealm;
+    private EncryptionKey key;
+    private KerberosTime authTime;
+    private KerberosTime startTime;
+    private KerberosTime endTime;
+    private KerberosTime renewTill;
+    private HostAddresses clientAddresses;
+    private AuthorizationData authzData;
+    private boolean isEncInSKey;
+    private TicketFlags ticketFlags;
+    private Ticket ticket;
+    private Ticket secondTicket;
+
+    public Credential() {
+
+    }
+
+    public Credential(TgtTicket tgt) {
+        PrincipalName clientPrincipal = tgt.getClientPrincipal();
+
+        clientPrincipal.setRealm(tgt.getRealm());
+
+        init(tgt, clientPrincipal);
+    }
+
+    public Credential(AbstractServiceTicket tkt, PrincipalName clientPrincipal) {
+        init(tkt, clientPrincipal);
+    }
+
+    private void init(AbstractServiceTicket tkt, PrincipalName clientPrincipal) {
+        EncKdcRepPart kdcRepPart = tkt.getEncKdcRepPart();
+
+        this.serverName = kdcRepPart.getSname();
+        this.serverRealm = kdcRepPart.getSrealm();
+        this.serverName.setRealm(serverRealm);
+
+        this.clientName = clientPrincipal;
+
+        this.key = kdcRepPart.getKey();
+        this.authTime = kdcRepPart.getAuthTime();
+        this.startTime = kdcRepPart.getStartTime();
+        this.endTime = kdcRepPart.getEndTime();
+
+        this.renewTill = kdcRepPart.getRenewTill();
+
+        this.ticketFlags = kdcRepPart.getFlags();
+        this.clientAddresses = kdcRepPart.getCaddr();
+
+        this.ticket = tkt.getTicket();
+
+        this.isEncInSKey = false;
+
+        this.secondTicket = null;
+    }
+
+    public PrincipalName getServicePrincipal() {
+        return serverName;
+    }
+
+    public KerberosTime getAuthTime() {
+        return authTime;
+    }
+
+    public KerberosTime getEndTime() {
+        return endTime;
+    }
+
+    public int getEType() {
+        return key.getKeyType().getValue();
+    }
+
+    public PrincipalName getClientName() {
+        return clientName;
+    }
+
+    public PrincipalName getServerName() {
+        return serverName;
+    }
+
+    public String getClientRealm() {
+        return clientRealm;
+    }
+
+    public EncryptionKey getKey() {
+        return key;
+    }
+
+    public KerberosTime getStartTime() {
+        return startTime;
+    }
+
+    public KerberosTime getRenewTill() {
+        return renewTill;
+    }
+
+    public HostAddresses getClientAddresses() {
+        return clientAddresses;
+    }
+
+    public AuthorizationData getAuthzData() {
+        return authzData;
+    }
+
+    public boolean isEncInSKey() {
+        return isEncInSKey;
+    }
+
+    public TicketFlags getTicketFlags() {
+        return ticketFlags;
+    }
+
+    public Ticket getTicket() {
+        return ticket;
+    }
+
+    public Ticket getSecondTicket() {
+        return secondTicket;
+    }
+
+    public void load(CredCacheInputStream ccis, int version) throws IOException {
+        this.clientName = ccis.readPrincipal(version);
+        if (clientName == null) {
+            throw new IOException("Invalid client principal name");
+        }
+
+        this.serverName = ccis.readPrincipal(version);
+        if (serverName == null) {
+            throw new IOException("Invalid server principal name");
+        }
+
+        boolean isConfEntry = false;
+
+        if (serverName.getRealm().equals(CONF_REALM)) {
+            isConfEntry = true;
+        }
+
+        this.key = ccis.readKey(version);
+
+        KerberosTime[] times = ccis.readTimes();
+        this.authTime = times[0];
+        this.startTime = times[1];
+        this.endTime = times[2];
+        this.renewTill = times[3];
+
+        this.isEncInSKey = ccis.readIsSkey();
+
+        this.ticketFlags = ccis.readTicketFlags();
+
+        this.clientAddresses = ccis.readAddr();
+
+        this.authzData = ccis.readAuthzData();
+
+        if (isConfEntry) {
+            byte[] confData = ccis.readCountedOctets();
+            // ignoring confData for now
+        } else {
+            this.ticket = ccis.readTicket();
+        }
+
+        this.secondTicket = ccis.readTicket();
+
+        // might skip krb5_ccache_conf_data/fast_avail/krbtgt/REALM@REALM in MIT KRB5
+    }
+
+    public void store(CredCacheOutputStream ccos, int version) throws IOException {
+        ccos.writePrincipal(clientName, version);
+        ccos.writePrincipal(serverName, version);
+        ccos.writeKey(key, version);
+
+        ccos.writeTimes(new KerberosTime[]{authTime, startTime, endTime, renewTill});
+
+        ccos.writeIsSkey(isEncInSKey);
+ 
+        ccos.writeTicketFlags(ticketFlags);
+
+        ccos.writeAddresses(clientAddresses);
+
+        ccos.writeAuthzData(authzData);
+
+        ccos.writeTicket(ticket);
+
+        ccos.writeTicket(secondTicket);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredentialCache.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredentialCache.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredentialCache.java
new file mode 100644
index 0000000..cec12f2
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/CredentialCache.java
@@ -0,0 +1,259 @@
+package org.apache.kerberos.kerb.ccache;
+
+import org.apache.kerberos.kerb.spec.common.PrincipalName;
+import org.apache.kerberos.kerb.spec.ticket.Ticket;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CredentialCache implements KrbCredentialCache
+{
+    public static final int FCC_FVNO_1 = 0x501;
+    public static final int FCC_FVNO_2 = 0x502;
+    public static final int FCC_FVNO_3 = 0x503;
+    public static final int FCC_FVNO_4 = 0x504;
+
+    public static final int FCC_TAG_DELTATIME = 1;
+    public static final int NT_UNKNOWN = 0;
+    public static final int MAXNAMELENGTH = 1024;
+
+    private int version = FCC_FVNO_4;
+    private List<Tag> tags;
+    private PrincipalName primaryPrincipal;
+    private List<Credential> credentials = new ArrayList<Credential> ();
+
+    @Override
+    public void store(File ccacheFile) throws IOException {
+        OutputStream outputStream = new FileOutputStream(ccacheFile);
+
+        store(outputStream);
+    }
+
+    @Override
+    public void store(OutputStream outputStream) throws IOException {
+        if (outputStream == null) {
+            throw new IllegalArgumentException("Invalid and null output stream");
+        }
+
+        CredCacheOutputStream ccos = new CredCacheOutputStream(outputStream);
+
+        doStore(ccos);
+
+        ccos.close();
+    }
+
+    private void doStore(CredCacheOutputStream ccos) throws IOException {
+        this.version = FCC_FVNO_3;
+
+        writeVersion(ccos);
+
+        if (version == FCC_FVNO_4) {
+            writeTags(ccos);
+        }
+
+        ccos.writePrincipal(primaryPrincipal, version);
+
+        for (Credential cred : credentials) {
+            cred.store(ccos, version);
+        }
+    }
+
+    @Override
+    public void setVersion(int version) {
+        this.version = version;
+    }
+
+    @Override
+    public PrincipalName getPrimaryPrincipal() {
+        return primaryPrincipal;
+    }
+
+    @Override
+    public void setPrimaryPrincipal(PrincipalName principal) {
+        primaryPrincipal = principal;
+    }
+
+    @Override
+    public int getVersion() {
+        return version;
+    }
+
+    public void setTags(List<Tag> tags) {
+        this.tags = tags;
+    }
+
+    public List<Tag> getTags() {
+        return this.tags;
+    }
+
+    @Override
+    public List<Credential> getCredentials() {
+        return credentials;
+    }
+
+    @Override
+    public void addCredential(Credential credential) {
+        if (credential != null) {
+            this.credentials.add(credential);
+        }
+    }
+
+    @Override
+    public void addCredentials(List<Credential> credentials) {
+        if (credentials != null) {
+            this.credentials.addAll(credentials);
+        }
+    }
+
+    @Override
+    public void removeCredentials(List<Credential> credentials) {
+        if (credentials != null) {
+            for (Credential cred : credentials) {
+                removeCredential(cred);
+            }
+        }
+    }
+
+    @Override
+    public void removeCredential(Credential credential) {
+        if (credential != null) {
+            for (Credential cred : credentials) {
+                if (cred.equals(credential)) {
+                    credentials.remove(cred);
+                    break;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void load(File ccacheFile) throws IOException {
+        if (! ccacheFile.exists() || ! ccacheFile.canRead()) {
+            throw new IllegalArgumentException("Invalid ccache file: " + ccacheFile.getAbsolutePath());
+        }
+
+        InputStream inputStream = new FileInputStream(ccacheFile);
+
+        load(inputStream);
+    }
+
+    @Override
+    public void load(InputStream inputStream) throws IOException {
+        if (inputStream == null) {
+            throw new IllegalArgumentException("Invalid and null input stream");
+        }
+
+        CredCacheInputStream ccis = new CredCacheInputStream(inputStream);
+
+        doLoad(ccis);
+
+        ccis.close();
+    }
+
+    private void doLoad(CredCacheInputStream ccis) throws IOException {
+        this.version = readVersion(ccis);
+
+        this.tags = readTags(ccis);
+
+        this.primaryPrincipal = ccis.readPrincipal(version);
+
+        this.credentials = readCredentials(ccis);
+    }
+
+    private List<Credential> readCredentials(CredCacheInputStream ccis) throws IOException {
+        List<Credential> results = new ArrayList<Credential>(2);
+
+        Credential cred;
+        while (ccis.available() > 0) {
+            cred =  new Credential();
+            cred.load(ccis, version);
+
+            results.add(cred);
+        }
+
+        return results;
+    }
+
+    private int readVersion(CredCacheInputStream ccis) throws IOException {
+        int result = ccis.readShort();
+        return result;
+    }
+
+    private List<Tag> readTags(CredCacheInputStream ccis) throws IOException {
+        int len = ccis.readShort();
+        List<Tag> tags = new ArrayList<Tag>();
+
+        int tag, tagLen, time, usec;
+        while (len > 0) {
+            tag = ccis.readShort();
+            tagLen = ccis.readShort();
+            switch (tag) {
+                case FCC_TAG_DELTATIME:
+                    time = ccis.readInt();
+                    usec = ccis.readInt();
+                    tags.add(new Tag(tag, time, usec));
+                    break;
+                default:
+                    ccis.read(new byte[tagLen], 0, tagLen); // ignore unknown tag
+            }
+            len = len - (4 + tagLen);
+        }
+
+        return tags;
+    }
+
+    private void writeVersion(CredCacheOutputStream ccos) throws IOException {
+        ccos.writeShort(version);
+    }
+
+    private void writeTags(CredCacheOutputStream ccos) throws IOException {
+        if (tags == null) {
+            ccos.writeShort(0);
+            return;
+        }
+
+        int length = 0;
+        for (Tag tag : tags) {
+            if (tag.tag != FCC_TAG_DELTATIME) {
+                continue;
+            }
+            length += tag.length;
+        }
+        ccos.writeShort(length);
+
+        for (Tag tag : tags) {
+            if (tag.tag != CredentialCache.FCC_TAG_DELTATIME) {
+                continue;
+            }
+            writeTag(ccos, tag);
+        }
+    }
+
+    private void writeTag(CredCacheOutputStream ccos, Tag tag) throws IOException {
+        ccos.writeShort(tag.tag);
+        ccos.writeShort(tag.length);
+        ccos.writeInt(tag.time);
+        ccos.writeInt(tag.usec);
+    }
+
+    public static void main(String[] args) throws IOException {
+        if (args.length != 2) {
+            System.err.println("Dump credential cache file");
+            System.err.println("Usage: CredentialCache <ccache-file>");
+            System.exit(1);
+        }
+
+        String cacheFile = args[1];
+        CredentialCache cc = new CredentialCache();
+        cc.load(new File(cacheFile));
+
+        Ticket tkt;
+        for (Credential cred : cc.getCredentials()) {
+            tkt = cred.getTicket();
+            System.out.println("Tkt server name: " + tkt.getSname().getName());
+            System.out.println("Tkt client name: " + cred.getClientName().getName());
+            System.out.println("Tkt encrypt type: " + tkt.getEncryptedEncPart().getEType().getName());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/KrbCredentialCache.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/KrbCredentialCache.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/KrbCredentialCache.java
new file mode 100644
index 0000000..959b548
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/KrbCredentialCache.java
@@ -0,0 +1,38 @@
+package org.apache.kerberos.kerb.ccache;
+
+import org.apache.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+public interface KrbCredentialCache {
+
+    public PrincipalName getPrimaryPrincipal();
+
+    public void setPrimaryPrincipal(PrincipalName principal);
+
+    public int getVersion();
+
+    public void setVersion(int version);
+
+    public List<Credential> getCredentials();
+
+    public void addCredential(Credential credential);
+
+    public void addCredentials(List<Credential> credentials);
+
+    public void removeCredentials(List<Credential> credentials);
+
+    public void removeCredential(Credential credential);
+
+    public void load(File ccacheFile) throws IOException;
+
+    public void load(InputStream inputStream) throws IOException;
+
+    public void store(File ccacheFile) throws IOException;
+
+    public void store(OutputStream outputStream) throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/Tag.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/Tag.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/Tag.java
new file mode 100644
index 0000000..317f5a0
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/Tag.java
@@ -0,0 +1,15 @@
+package org.apache.kerberos.kerb.ccache;
+
+public class Tag {
+    int tag = 0;
+    int tagLen = 8;
+    int time = 0;
+    int usec = 0;
+    int length = 2 + 2 + 8; // len(tag) + len(tagLen) + len(tagData);
+
+    public Tag(int tag, int time, int usec) {
+        this.tag = tag;
+        this.time = time;
+        this.usec = usec;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/ccache.txt
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/ccache.txt b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/ccache.txt
new file mode 100644
index 0000000..91453ea
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/ccache/ccache.txt
@@ -0,0 +1,98 @@
+The Kerberos Credential Cache Binary File Format
+Copyright (C) 2006-2013 Simon Josefsson <simon josefsson.org>
+http://josefsson.org/shishi/ccache.txt
+Last updated: Sat Sep 23 12:04:11 CEST 2006
+
+Like the MIT keytab binary format (see Michael B Allen's reverse
+engineered description in keytab.txt), the credential cache format is
+not standard nor documented anywhere.
+
+In C style notation, the MIT credential cache file format is as
+follows.  All values are in network byte order.  All text is ASCII.
+
+ccache {
+          uint16_t file_format_version; /* 0x0504 */
+          uint16_t headerlen;           /* only if version is 0x0504 */
+          header headers[];             /* only if version is 0x0504 */
+          principal primary_principal;
+          credential credentials[*];
+};
+
+header {
+       uint16_t tag;                    /* 1 = DeltaTime */
+       uint16_t taglen;
+       uint8_t tagdata[taglen]
+};
+
+The ccache.taglen and ccache.tags fields are only present in 0x0504
+versions, not in earlier.  Both MIT and Heimdal appear to correctly
+ignore unknown tags, so it appears safe to add them (although there is
+no central place to "register" tags).
+
+Currently only one tag is widely implemented, DeltaTime (0x0001).  Its
+taglen is always 8, and tagdata will contain:
+
+DeltaTime {
+       uint32_t time_offset;
+       uint32_t usec_offset;
+};
+
+After reading the file_format_version, header tags, and default
+principal, a list of credentials follow.  You deduce from the file
+length when there are no more credentials.
+
+credential {
+           principal client;
+           principal server;
+           keyblock key;
+           times    time;
+           uint8_t  is_skey;            /* 1 if skey, 0 otherwise */
+           uint32_t tktflags;           /* stored in reversed byte order */
+           uint32_t num_address;
+           address  addrs[num_address];
+           uint32_t num_authdata;
+           authdata authdata[num_authdata];
+           counted_octet_string ticket;
+           counted_octet_string second_ticket;
+};
+
+keyblock {
+         uint16_t keytype;
+         uint16_t etype;                /* only present if version 0x0503 */
+         uint32_t keylen;               /* [drankye]: corrected, before it was uint16_t */
+         uint8_t keyvalue[keylen];
+};
+
+times {
+      uint32_t  authtime;
+      uint32_t  starttime;
+      uint32_t  endtime;
+      uint32_t  renew_till;
+};
+
+address {
+        uint16_t addrtype;
+        counted_octet_string addrdata;
+};
+
+authdata {
+         uint16_t authtype;
+         counted_octet_string authdata;
+};
+
+principal {
+          uint32_t name_type;           /* not present if version 0x0501 */
+          uint32_t num_components;      /* sub 1 if version 0x501 */
+          counted_octet_string realm;
+          counted_octet_string components[num_components];
+};
+
+counted_octet_string {
+    uint32_t length;
+    uint8_t data[length];
+};
+
+Permission to copy, modify, and distribute this document, with or
+without modification, for any purpose and without fee or royalty is
+hereby granted, provided that you include this copyright notice in ALL
+copies of the document or portions thereof, including modifications.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/Keytab.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/Keytab.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/Keytab.java
new file mode 100644
index 0000000..f20852f
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/Keytab.java
@@ -0,0 +1,178 @@
+package org.apache.kerberos.kerb.keytab;
+
+import org.apache.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerberos.kerb.spec.common.EncryptionType;
+import org.apache.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.util.*;
+
+public class Keytab implements KrbKeytab {
+
+    public static final int V501 = 0x0501;
+    public static final int V502 = 0x0502;
+
+    private int version = V502;
+
+    private Map<PrincipalName, List<KeytabEntry>> principalEntries;
+
+    public Keytab() {
+        this.principalEntries = new HashMap<PrincipalName, List<KeytabEntry>>();
+    }
+
+    @Override
+    public List<PrincipalName> getPrincipals() {
+        return new ArrayList<PrincipalName>(principalEntries.keySet());
+    }
+
+    @Override
+    public void addKeytabEntries(List<KeytabEntry> entries) {
+        for (KeytabEntry entry : entries) {
+            addEntry(entry);
+        }
+    }
+
+    @Override
+    public void removeKeytabEntries(PrincipalName principal) {
+        principalEntries.remove(principal);
+    }
+
+    @Override
+    public void removeKeytabEntry(KeytabEntry entry) {
+        PrincipalName principal = entry.getPrincipal();
+        List<KeytabEntry> entries = principalEntries.get(principal);
+        if (entries != null) {
+            Iterator<KeytabEntry> iter = entries.iterator();
+            KeytabEntry tmp;
+            while (iter.hasNext()) {
+                tmp = iter.next();
+                if (entry.equals(tmp)) {
+                    iter.remove();
+                    break;
+                }
+            }
+        }
+    }
+
+    @Override
+    public List<KeytabEntry> getKeytabEntries(PrincipalName principal) {
+        return principalEntries.get(principal);
+    }
+
+    @Override
+    public EncryptionKey getKey(PrincipalName principal, EncryptionType keyType) {
+        List<KeytabEntry> entries = getKeytabEntries(principal);
+        for (KeytabEntry ke : entries) {
+            if (ke.getKey().getKeyType() == keyType) {
+                return ke.getKey();
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public void load(File keytabFile) throws IOException {
+        if (! keytabFile.exists() || ! keytabFile.canRead()) {
+            throw new IllegalArgumentException("Invalid keytab file: " + keytabFile.getAbsolutePath());
+        }
+
+        InputStream is = new FileInputStream(keytabFile);
+
+        load(is);
+    }
+
+    @Override
+    public void load(InputStream inputStream) throws IOException {
+        if (inputStream == null) {
+            throw new IllegalArgumentException("Invalid and null input stream");
+        }
+
+        KeytabInputStream kis = new KeytabInputStream(inputStream);
+
+        doLoad(kis);
+    }
+
+    private void doLoad(KeytabInputStream kis) throws IOException {
+        this.version = readVersion(kis);
+
+        List<KeytabEntry> entries = readEntries(kis);
+        addKeytabEntries(entries);
+    }
+
+    @Override
+    public void addEntry(KeytabEntry entry) {
+        PrincipalName principal = entry.getPrincipal();
+        List<KeytabEntry> entries = principalEntries.get(principal);
+        if (entries == null) {
+            entries = new ArrayList<KeytabEntry>();
+            principalEntries.put(principal, entries);
+        }
+        entries.add(entry);
+    }
+
+    private int readVersion(KeytabInputStream kis) throws IOException {
+        return kis.readShort();
+    }
+
+    private List<KeytabEntry> readEntries(KeytabInputStream kis) throws IOException {
+        List<KeytabEntry> entries = new ArrayList<KeytabEntry>();
+
+        int entrySize;
+        ByteBuffer entryData;
+        KeytabEntry entry;
+        while (kis.available() > 0) {
+            entrySize = kis.readInt();
+            if (kis.available() < entrySize) {
+                throw new IOException("Bad input stream with less data than expected: " + entrySize);
+            }
+            entry = readEntry(kis);
+            entries.add(entry);
+        }
+
+        return entries;
+    }
+
+    private KeytabEntry readEntry(KeytabInputStream kis) throws IOException {
+        KeytabEntry entry = new KeytabEntry();
+        entry.load(kis, version);
+        return entry;
+    }
+
+    @Override
+    public void store(File keytabFile) throws IOException {
+        OutputStream outputStream = new FileOutputStream(keytabFile);
+
+        store(outputStream);
+    }
+
+    @Override
+    public void store(OutputStream outputStream) throws IOException {
+        if (outputStream == null) {
+            throw new IllegalArgumentException("Invalid and null output stream");
+        }
+
+        KeytabOutputStream kos = new KeytabOutputStream(outputStream);
+
+        writeVersion(kos);
+        writeEntries(kos);
+    }
+
+    private void writeVersion(KeytabOutputStream kos) throws IOException {
+        byte[] bytes = new byte[2];
+        bytes[0] = (byte) 0x05;
+        bytes[1] = version == V502 ? (byte) 0x02 : (byte) 0x01;
+
+        kos.write(bytes);
+    }
+
+    private void writeEntries(KeytabOutputStream kos) throws IOException {
+        for (PrincipalName principal : principalEntries.keySet()) {
+            for (KeytabEntry entry : principalEntries.get(principal)) {
+                entry.store(kos);
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabEntry.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabEntry.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabEntry.java
new file mode 100644
index 0000000..b0e6558
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabEntry.java
@@ -0,0 +1,102 @@
+package org.apache.kerberos.kerb.keytab;
+
+import org.apache.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class KeytabEntry
+{
+    private PrincipalName principal;
+    private KerberosTime timestamp;
+    private int kvno;
+    private EncryptionKey key;
+
+    public KeytabEntry(PrincipalName principal, KerberosTime timestamp,
+                       int kvno, EncryptionKey key) {
+        this.principal = principal;
+        this.timestamp = timestamp;
+        this.kvno = kvno;
+        this.key = key;
+    }
+
+    public KeytabEntry() {
+
+    }
+
+    public void load(KeytabInputStream kis, int version) throws IOException {
+        this.principal = kis.readPrincipal(version);
+
+        this.timestamp = kis.readTime();
+
+        this.kvno = kis.readByte();
+
+        this.key = kis.readKey();
+    }
+
+    public void store(KeytabOutputStream kos) throws IOException {
+        byte[] body = null;
+
+        // compute entry body content first so that to get and write the size
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        KeytabOutputStream subKos = new KeytabOutputStream(baos);
+        writeBody(subKos, 0); // todo: consider the version
+        subKos.flush();
+        body = baos.toByteArray();
+
+        kos.writeInt(body.length);
+        kos.write(body);
+    }
+
+    public EncryptionKey getKey() {
+        return key;
+    }
+
+    public int getKvno() {
+        return kvno;
+    }
+
+    public PrincipalName getPrincipal() {
+        return principal;
+    }
+
+    public KerberosTime getTimestamp() {
+        return timestamp;
+    }
+
+    public void writeBody(KeytabOutputStream kos, int version) throws IOException {
+        kos.writePrincipal(principal, version);
+
+        kos.writeTime(timestamp);
+
+        kos.writeByte(kvno);
+
+        kos.writeKey(key, version);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        KeytabEntry that = (KeytabEntry) o;
+
+        if (kvno != that.kvno) return false;
+        if (!key.equals(that.key)) return false;
+        if (!principal.equals(that.principal)) return false;
+        if (!timestamp.equals(that.timestamp)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = principal.hashCode();
+        result = 31 * result + timestamp.hashCode();
+        result = 31 * result + kvno;
+        result = 31 * result + key.hashCode();
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabInputStream.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabInputStream.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabInputStream.java
new file mode 100644
index 0000000..28cf1f1
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabInputStream.java
@@ -0,0 +1,70 @@
+package org.apache.kerberos.kerb.keytab;
+
+import org.apache.kerberos.kerb.KrbInputStream;
+import org.apache.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerberos.kerb.spec.common.EncryptionType;
+import org.apache.kerberos.kerb.spec.common.NameType;
+import org.apache.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class KeytabInputStream extends KrbInputStream
+{
+    public KeytabInputStream(InputStream in) {
+        super(in);
+    }
+
+    public KerberosTime readTime() throws IOException {
+        long value = readInt();
+        KerberosTime time = new KerberosTime(value * 1000);
+        return time;
+    }
+
+    @Override
+    public PrincipalName readPrincipal(int version) throws IOException {
+        int numComponents = readShort();
+        if (version == Keytab.V501) {
+            numComponents -= 1;
+        }
+
+        String realm = readCountedString();
+
+        List<String> nameStrings = new ArrayList<String>();
+        String component;
+        for (int i = 0; i < numComponents; i++) { // sub 1 if version 0x501
+            component = readCountedString();
+            nameStrings.add(component);
+        }
+        int type = readInt(); // not present if version 0x501
+        NameType nameType = NameType.fromValue(type);
+        PrincipalName principal = new PrincipalName(nameStrings, nameType);
+        principal.setRealm(realm);
+
+        return principal;
+    }
+
+    public EncryptionKey readKey() throws IOException {
+        int eType = readShort();
+        EncryptionType encryptionType = EncryptionType.fromValue(eType);
+
+        byte[] keyData = readCountedOctets();
+        EncryptionKey key = new EncryptionKey(encryptionType, keyData);
+
+        return key;
+    }
+
+    public String readCountedString() throws IOException {
+        byte[] countedOctets = readCountedOctets();
+        // ASCII
+        return new String(countedOctets);
+    }
+
+    @Override
+    public int readOctetsCount() throws IOException {
+        return readShort();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabOutputStream.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabOutputStream.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabOutputStream.java
new file mode 100644
index 0000000..01bd17d
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KeytabOutputStream.java
@@ -0,0 +1,44 @@
+package org.apache.kerberos.kerb.keytab;
+
+import org.apache.kerberos.kerb.KrbOutputStream;
+import org.apache.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+public class KeytabOutputStream extends KrbOutputStream
+{
+	public KeytabOutputStream(OutputStream out) {
+        super(out);
+    }
+
+    public void writePrincipal(PrincipalName principal, int version) throws IOException {
+        List<String> nameStrings = principal.getNameStrings();
+        int numComponents = principal.getNameStrings().size();
+        String realm = principal.getRealm();
+
+        writeShort(numComponents);
+
+        writeCountedString(realm);
+
+        for (String nameCom : nameStrings) {
+            writeCountedString(nameCom);
+        }
+
+        writeInt(principal.getNameType().getValue()); // todo: consider the version
+    }
+
+    @Override
+    public void writeKey(EncryptionKey key, int version) throws IOException {
+    	writeShort(key.getKeyType().getValue());
+        writeCountedOctets(key.getKeyData());
+    }
+
+    @Override
+    public void writeCountedOctets(byte[] data) throws IOException {
+        writeShort(data.length);
+        write(data);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/967d7e1c/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KrbKeytab.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KrbKeytab.java b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KrbKeytab.java
new file mode 100644
index 0000000..a31e4ab
--- /dev/null
+++ b/haox-kerb/kerb-util/src/main/java/org/apache/kerberos/kerb/keytab/KrbKeytab.java
@@ -0,0 +1,36 @@
+package org.apache.kerberos.kerb.keytab;
+
+import org.apache.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerberos.kerb.spec.common.EncryptionType;
+import org.apache.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+public interface KrbKeytab {
+
+    public List<PrincipalName> getPrincipals();
+
+    public void addKeytabEntries(List<KeytabEntry> entries);
+
+    public void removeKeytabEntries(PrincipalName principal);
+
+    public void removeKeytabEntry(KeytabEntry entry);
+
+    public List<KeytabEntry> getKeytabEntries(PrincipalName principal);
+
+    public EncryptionKey getKey(PrincipalName principal, EncryptionType keyType);
+
+    public void load(File keytabFile) throws IOException;
+
+    public void load(InputStream inputStream) throws IOException;
+
+    void addEntry(KeytabEntry entry);
+
+    public void store(File keytabFile) throws IOException;
+
+    public void store(OutputStream outputStream) throws IOException;
+}