You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by pl...@apache.org on 2015/05/27 10:22:38 UTC

directory-kerby git commit: [DIRKRB-126]-Implementing TokenPreauth mechanism.

Repository: directory-kerby
Updated Branches:
  refs/heads/master c0f382089 -> f46f994f9


[DIRKRB-126]-Implementing TokenPreauth mechanism.


Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/f46f994f
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/f46f994f
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/f46f994f

Branch: refs/heads/master
Commit: f46f994f9046fef28071b4798054c35dd029631d
Parents: c0f3820
Author: plusplusjiajia <ji...@intel.com>
Authored: Wed May 27 16:27:06 2015 +0800
Committer: plusplusjiajia <ji...@intel.com>
Committed: Wed May 27 16:27:06 2015 +0800

----------------------------------------------------------------------
 .../kerby/kerberos/kdc/WithTokenKdcTest.java    | 62 +++++++++++---
 .../kerby/kerberos/kerb/client/KrbClient.java   |  3 +-
 .../client/impl/AbstractInternalKrbClient.java  |  2 +
 .../kerb/client/preauth/token/TokenPreauth.java | 58 ++++++++++---
 .../kerb/client/request/ArmoredAsRequest.java   |  2 -
 .../kerberos/kerb/client/request/AsRequest.java |  6 +-
 .../kerb/client/request/AsRequestWithToken.java |  8 +-
 .../kerb/client/request/TgsRequest.java         |  2 +-
 .../kerby/kerberos/kerb/spec/KerberosTime.java  | 15 +++-
 .../kerby/kerberos/kerb/spec/base/KeyUsage.java |  4 +-
 .../kerby/kerberos/kerb/spec/base/KrbToken.java | 18 +++--
 .../kerby/kerberos/kerb/server/KdcTestBase.java |  6 +-
 .../kerby/kerberos/kerb/server/KdcConfig.java   |  4 +
 .../kerberos/kerb/server/KdcConfigKey.java      |  1 +
 .../kerb/server/preauth/PreauthHandler.java     | 15 +++-
 .../kerb/server/preauth/token/TokenPreauth.java | 79 ++++++++++++++++++
 .../kerberos/kerb/server/request/AsRequest.java | 38 +++++++--
 .../kerb/server/request/KdcRequest.java         | 85 +++++++++++++++-----
 .../kerb/server/request/TgsRequest.java         | 29 +++++--
 .../kerb/server/request/TickertIssuer.java      |  8 +-
 .../kerby/kerberos/kerb/ccache/Credential.java  |  3 +-
 21 files changed, 367 insertions(+), 81 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/WithTokenKdcTest.java
----------------------------------------------------------------------
diff --git a/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/WithTokenKdcTest.java b/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/WithTokenKdcTest.java
index dce118c..3af335c 100644
--- a/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/WithTokenKdcTest.java
+++ b/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/WithTokenKdcTest.java
@@ -21,14 +21,19 @@ package org.apache.kerby.kerberos.kdc;
 
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.KrbRuntime;
+import org.apache.kerby.kerberos.kerb.ccache.Credential;
+import org.apache.kerby.kerberos.kerb.ccache.CredentialCache;
 import org.apache.kerby.kerberos.kerb.provider.TokenEncoder;
 import org.apache.kerby.kerberos.kerb.server.KdcTestBase;
+import org.apache.kerby.kerberos.kerb.spec.base.AuthToken;
 import org.apache.kerby.kerberos.kerb.spec.ticket.ServiceTicket;
 import org.apache.kerby.kerberos.kerb.spec.ticket.TgtTicket;
-import org.apache.kerby.kerberos.kerb.spec.base.AuthToken;
 import org.apache.kerby.kerberos.provider.token.JwtTokenProvider;
 import org.junit.Before;
+import org.junit.Test;
 
+import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -36,11 +41,13 @@ import java.util.List;
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class WithTokenKdcTest extends KdcTestBase {
+
     static final String SUBJECT = "test-sub";
     static final String AUDIENCE = "krbtgt@EXAMPLE.COM";
     static final String ISSUER = "oauth2.com";
     static final String GROUP = "sales-group";
     static final String ROLE = "ADMIN";
+    private File cCacheFile;
 
     private TokenEncoder tokenEncoder;
 
@@ -83,24 +90,61 @@ public class WithTokenKdcTest extends KdcTestBase {
     @Override
     protected void prepareKdcServer() throws Exception {
         super.prepareKdcServer();
-        kdcServer.createPrincipals(clientPrincipal);
     }
 
-    //@Test
+    @Override
+    protected void createPrincipals() {
+        super.createPrincipals();
+        kdcServer.createPrincipal(clientPrincipal, TEST_PASSWORD);
+    }
+
+    @Test
     public void testKdc() throws Exception {
         kdcServer.start();
         krbClnt.init();
 
-        TgtTicket tgt;
+        createCredentialCache(clientPrincipal, TEST_PASSWORD);
+
+        TgtTicket tgt = null;
         try {
-            tgt = krbClnt.requestTgtWithToken(authToken);
-        } catch (KrbException te) {
-            assertThat(te.getMessage().contains("timeout")).isTrue();
+            tgt = krbClnt.requestTgtWithToken(authToken, cCacheFile.getPath());
+        } catch (KrbException e) {
+            assertThat(e.getMessage().contains("timeout")).isTrue();
             return;
         }
-        assertThat(tgt).isNull();
+        assertThat(tgt).isNotNull();
+        assertThat(tgt.getClientPrincipal()).isEqualTo(SUBJECT + "@" + kdcRealm);
+        assertThat(tgt.getRealm()).isEqualTo(kdcRealm);
+        assertThat(tgt.getTicket()).isNotNull();
+        assertThat(tgt.getEncKdcRepPart()).isNotNull();
+        assertThat(tgt.getSessionKey()).isNotNull();
 
         ServiceTicket tkt = krbClnt.requestServiceTicketWithTgt(tgt, serverPrincipal);
-        assertThat(tkt).isNull();
+        assertThat(tkt).isNotNull();
+        assertThat(tkt.getRealm()).isEqualTo(kdcRealm);
+        assertThat(tkt.getTicket()).isNotNull();
+        assertThat(tkt.getSessionKey()).isNotNull();
+        assertThat(tkt.getEncKdcRepPart()).isNotNull();
+    }
+
+    private void createCredentialCache(String principal,
+                                       String password) throws Exception {
+        TgtTicket tgt = krbClnt.requestTgtWithPassword(principal, password);
+        writeTgtToCache(tgt, principal);
+    }
+
+    /**
+     * Write tgt into credentials cache.
+     */
+    private void writeTgtToCache(
+            TgtTicket tgt, String principal) throws IOException {
+        Credential credential = new Credential(tgt);
+        CredentialCache cCache = new CredentialCache();
+        cCache.addCredential(credential);
+        cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
+
+        String fileName = "krb5_" + principal + ".cc";
+        cCacheFile = new File(getTestDir().getPath(), fileName);
+        cCache.store(cCacheFile);
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbClient.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbClient.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbClient.java
index 55a0c9c..3ca2407 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbClient.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbClient.java
@@ -218,13 +218,14 @@ public class KrbClient {
      * @return TGT
      * @throws KrbException
      */
-    public TgtTicket requestTgtWithToken(AuthToken token) throws KrbException {
+    public TgtTicket requestTgtWithToken(AuthToken token, String armorCache) throws KrbException {
         if (! token.isIdToken()) {
             throw new IllegalArgumentException("Identity token is expected");
         }
 
         KOptions requestOptions = new KOptions();
         requestOptions.add(KrbOption.TOKEN_USER_ID_TOKEN, token);
+        requestOptions.add(KrbOption.ARMOR_CACHE, armorCache);
         return requestTgtWithOptions(requestOptions);
     }
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/impl/AbstractInternalKrbClient.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/impl/AbstractInternalKrbClient.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/impl/AbstractInternalKrbClient.java
index 662f42a..5437174 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/impl/AbstractInternalKrbClient.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/impl/AbstractInternalKrbClient.java
@@ -116,6 +116,8 @@ public abstract class AbstractInternalKrbClient implements InternalKrbClient {
             asRequest = new AsRequestWithCert(context);
         } else if (requestOptions.contains(KrbOption.USE_TOKEN)) {
             asRequest = new AsRequestWithToken(context);
+        } else if (requestOptions.contains(KrbOption.TOKEN_USER_ID_TOKEN)) {
+            asRequest = new AsRequestWithToken(context);
         }
 
         if (asRequest == null) {

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/token/TokenPreauth.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/token/TokenPreauth.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/token/TokenPreauth.java
index 23269c6..840c0f1 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/token/TokenPreauth.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/token/TokenPreauth.java
@@ -19,21 +19,29 @@
  */
 package org.apache.kerby.kerberos.kerb.client.preauth.token;
 
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
 import org.apache.kerby.kerberos.kerb.client.KrbOption;
-import org.apache.kerby.KOptions;
 import org.apache.kerby.kerberos.kerb.client.preauth.AbstractPreauthPlugin;
-import org.apache.kerby.kerberos.kerb.preauth.PluginRequestContext;
 import org.apache.kerby.kerberos.kerb.client.request.KdcRequest;
+import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
 import org.apache.kerby.kerberos.kerb.preauth.PaFlag;
 import org.apache.kerby.kerberos.kerb.preauth.PaFlags;
+import org.apache.kerby.kerberos.kerb.preauth.PluginRequestContext;
 import org.apache.kerby.kerberos.kerb.preauth.token.TokenPreauthMeta;
-import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.spec.base.AuthToken;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptedData;
 import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
+import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
+import org.apache.kerby.kerberos.kerb.spec.base.KrbToken;
+import org.apache.kerby.kerberos.kerb.spec.base.TokenFormat;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaData;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaDataEntry;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaDataType;
-import org.apache.kerby.kerberos.kerb.spec.base.AuthToken;
+import org.apache.kerby.kerberos.kerb.spec.pa.token.PaTokenRequest;
+import org.apache.kerby.kerberos.kerb.spec.pa.token.TokenInfo;
 
 import java.util.Collections;
 import java.util.List;
@@ -93,16 +101,23 @@ public class TokenPreauth extends AbstractPreauthPlugin {
     public void tryFirst(KdcRequest kdcRequest,
                          PluginRequestContext requestContext,
                          PaData outPadata) throws KrbException {
-
+        if (kdcRequest.getAsKey() == null) {
+            kdcRequest.needAsKey();
+        }
+        outPadata.addElement(makeEntry(kdcRequest));
     }
 
     @Override
     public boolean process(KdcRequest kdcRequest,
-                        PluginRequestContext requestContext,
-                        PaDataEntry inPadata,
-                        PaData outPadata) throws KrbException {
+                           PluginRequestContext requestContext,
+                           PaDataEntry inPadata,
+                           PaData outPadata) throws KrbException {
 
-        return false;
+        if (kdcRequest.getAsKey() == null) {
+            kdcRequest.needAsKey();
+        }
+        outPadata.addElement(makeEntry(kdcRequest));
+        return true;
     }
 
     @Override
@@ -121,4 +136,27 @@ public class TokenPreauth extends AbstractPreauthPlugin {
 
         return paFlags;
     }
-}
+
+    private PaDataEntry makeEntry(KdcRequest kdcRequest) throws KrbException {
+        KOptions options = kdcRequest.getPreauthOptions();
+
+        KOption option = options.getOption(KrbOption.TOKEN_USER_ID_TOKEN);
+        AuthToken authToken = (AuthToken)option.getValue();
+
+        KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
+        PaTokenRequest tokenPa = new PaTokenRequest();
+        tokenPa.setToken(krbToken);
+        TokenInfo info = new TokenInfo();
+        info.setTokenVendor("vendor");
+        tokenPa.setTokenInfo(info);
+
+        EncryptedData paDataValue = EncryptionUtil.seal(tokenPa,
+            kdcRequest.getAsKey(), KeyUsage.PA_TOKEN);
+
+        PaDataEntry paDataEntry = new PaDataEntry();
+        paDataEntry.setPaDataType(PaDataType.TOKEN_REQUEST);
+        paDataEntry.setPaDataValue(paDataValue.encode());
+
+        return paDataEntry;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/ArmoredAsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/ArmoredAsRequest.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/ArmoredAsRequest.java
index 8ad5a88..a0cf189 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/ArmoredAsRequest.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/ArmoredAsRequest.java
@@ -30,7 +30,6 @@ import org.apache.kerby.kerberos.kerb.common.CheckSumUtil;
 import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
 import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
 import org.apache.kerby.kerberos.kerb.crypto.fast.FastUtil;
-import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
 import org.apache.kerby.kerberos.kerb.spec.ap.ApOptions;
 import org.apache.kerby.kerberos.kerb.spec.ap.ApReq;
 import org.apache.kerby.kerberos.kerb.spec.ap.Authenticator;
@@ -40,7 +39,6 @@ import org.apache.kerby.kerberos.kerb.spec.base.EncryptedData;
 import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
 import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
 import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
-import org.apache.kerby.kerberos.kerb.spec.base.PrincipalName;
 import org.apache.kerby.kerberos.kerb.spec.fast.ArmorType;
 import org.apache.kerby.kerberos.kerb.spec.fast.KrbFastArmor;
 import org.apache.kerby.kerberos.kerb.spec.fast.KrbFastArmoredReq;

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequest.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequest.java
index 5aeba91..073c2c8 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequest.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequest.java
@@ -23,6 +23,7 @@ import org.apache.kerby.kerberos.kerb.KrbErrorCode;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.ccache.CredentialCache;
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
+import org.apache.kerby.kerberos.kerb.client.KrbOption;
 import org.apache.kerby.kerberos.kerb.common.KrbUtil;
 import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
 import org.apache.kerby.kerberos.kerb.spec.base.HostAddress;
@@ -88,7 +89,8 @@ public class AsRequest extends KdcRequest {
         PrincipalName clientPrincipal = getKdcRep().getCname();
         String clientRealm = getKdcRep().getCrealm();
         clientPrincipal.setRealm(clientRealm);
-        if (! clientPrincipal.equals(getClientPrincipal())) {
+        if (!getKrbOptions().contains(KrbOption.TOKEN_USER_ID_TOKEN)
+            && !clientPrincipal.equals(getClientPrincipal())) {
             throw new KrbException(KrbErrorCode.KDC_ERR_CLIENT_NAME_MISMATCH);
         }
 
@@ -142,4 +144,4 @@ public class AsRequest extends KdcRequest {
 
         return cc;
     }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithToken.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithToken.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithToken.java
index 0d08415..cd1517d 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithToken.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithToken.java
@@ -19,7 +19,6 @@
  */
 package org.apache.kerby.kerberos.kerb.client.request;
 
-import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.KOptions;
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
 import org.apache.kerby.kerberos.kerb.client.KrbOption;
@@ -37,11 +36,6 @@ public class AsRequestWithToken extends ArmoredAsRequest {
     }
 
     @Override
-    public void process() throws KrbException {
-        throw new RuntimeException("To be implemented");
-    }
-
-    @Override
     public KOptions getPreauthOptions() {
         KOptions results = super.getPreauthOptions();
         KOptions krbOptions = getKrbOptions();
@@ -52,4 +46,4 @@ public class AsRequestWithToken extends ArmoredAsRequest {
 
         return results;
     }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequest.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequest.java
index c9d1144..f4367be 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequest.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequest.java
@@ -94,7 +94,7 @@ public class TgsRequest extends KdcRequest {
         EncryptedData authnData = EncryptionUtil.seal(authenticator,
                 sessionKey, KeyUsage.TGS_REQ_AUTH);
         apReq.setEncryptedAuthenticator(authnData);
-
+        apReq.setAuthenticator(authenticator);
         apReq.setTicket(tgt.getTicket());
         ApOptions apOptions = new ApOptions();
         apReq.setApOptions(apOptions);

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/KerberosTime.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/KerberosTime.java b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/KerberosTime.java
index 8ed8061..db105fe 100644
--- a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/KerberosTime.java
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/KerberosTime.java
@@ -57,12 +57,15 @@ public class KerberosTime extends Asn1GeneralizedTime {
     }
 
     /**
-     * time in milliseconds
+     * @param time set time in milliseconds
      */
     public void setTime(long time) {
         setValue(new Date(time));
     }
 
+    /**
+     * get the time in seconds
+     */
     public long getTimeInSeconds() {
         return getTime() / 1000;
     }
@@ -71,10 +74,16 @@ public class KerberosTime extends Asn1GeneralizedTime {
         return getValue().compareTo(ktime.getValue()) < 0;
     }
 
+    /**
+     * @param time in milliseconds
+     */
     public boolean lessThan(long time) {
-        return getValue().getTime() <= time * 1000;
+        return getValue().getTime() <= time;
     }
 
+    /**
+     * @param ktime compare with milliseconds
+     */
     public boolean greaterThan(KerberosTime ktime) {
         return getValue().compareTo(ktime.getValue()) > 0;
     }
@@ -125,4 +134,4 @@ public class KerberosTime extends Asn1GeneralizedTime {
     public int hashCode() {
         return getValue().hashCode();
     }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/KeyUsage.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/KeyUsage.java b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/KeyUsage.java
index 7f5a492..ba317b7 100644
--- a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/KeyUsage.java
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/KeyUsage.java
@@ -99,7 +99,9 @@ public enum KeyUsage implements KrbEnum
     FAST_FINISHED(53),
     ENC_CHALLENGE_CLIENT(54),
     ENC_CHALLENGE_KDC(55),
-    AS_REQ(56);
+    AS_REQ(56),
+    //PA-TOKEN padata,encrypted with the client key
+    PA_TOKEN(57);
 
     private int value;
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/KrbToken.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/KrbToken.java b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/KrbToken.java
index 686feb5..3bc5caa 100644
--- a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/KrbToken.java
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/spec/base/KrbToken.java
@@ -58,14 +58,20 @@ public class KrbToken extends KrbSequenceType implements AuthToken {
         super(fieldInfos);
     }
 
-    @Override
-    public void encode(ByteBuffer buffer) {
+    public KrbToken(AuthToken authToken, TokenFormat format) {
+        this();
+
+        this.innerToken = authToken;
+        setTokenFormat(format);
         try {
-            setTokenValue(getTokenEncoder().encodeAsBytes(this));
+            setTokenValue(getTokenEncoder().encodeAsBytes(innerToken));
         } catch (KrbException e) {
-            throw new RuntimeException(e);
+            throw new RuntimeException("Failed to encode AuthToken", e);
         }
-        super.encode(buffer);
+    }
+
+    public AuthToken getAuthToken() {
+        return innerToken;
     }
 
     @Override
@@ -192,6 +198,6 @@ public class KrbToken extends KrbSequenceType implements AuthToken {
 
     @Override
     public void addAttribute(String name, Object value) {
-
+        innerToken.addAttribute(name, value);
     }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-kdc-test/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-kdc-test/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java b/kerby-kerb/kerb-kdc-test/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
index 0389dd7..f1c7115 100644
--- a/kerby-kerb/kerb-kdc-test/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
+++ b/kerby-kerb/kerb-kdc-test/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
@@ -84,6 +84,10 @@ public abstract class KdcTestBase {
         FileUtils.deleteDirectory(TEST_DIR);
     }
 
+    public File getTestDir() {
+        return TEST_DIR;
+    }
+
     protected boolean allowUdp() {
         return true;
     }
@@ -194,7 +198,7 @@ public abstract class KdcTestBase {
             krbClnt.setKdcUdpPort(udpPort);
         }
 
-        krbClnt.setTimeout(50);
+        krbClnt.setTimeout(1000);
         krbClnt.setKdcRealm(kdcServer.getKdcRealm());
     }
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfig.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfig.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfig.java
index 216660b..15e2347 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfig.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfig.java
@@ -86,6 +86,10 @@ public class KdcConfig extends Conf {
         return getBoolean(KdcConfigKey.PREAUTH_REQUIRED);
     }
 
+    public boolean isAllowTokenPreauth() {
+        return getBoolean(KdcConfigKey.ALLOW_TOKEN_PREAUTH);
+    }
+
     public long getAllowableClockSkew() {
         return getLong(KdcConfigKey.ALLOWABLE_CLOCKSKEW);
     }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfigKey.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfigKey.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfigKey.java
index 1c05cd4..a2a3ed6 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfigKey.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcConfigKey.java
@@ -33,6 +33,7 @@ public enum KdcConfigKey implements SectionConfigKey {
     KDC_DOMAIN("example.com"),
     KDC_REALM("EXAMPLE.COM", "kdcdefaults"),
     PREAUTH_REQUIRED(true),
+    ALLOW_TOKEN_PREAUTH(true),
     ALLOWABLE_CLOCKSKEW(5 * 60L),
     EMPTY_ADDRESSES_ALLOWED(true),
     PA_ENC_TIMESTAMP_REQUIRED(true),

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthHandler.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthHandler.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthHandler.java
index 1d17105..ccd7a2e 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthHandler.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/PreauthHandler.java
@@ -19,11 +19,12 @@
  */
 package org.apache.kerby.kerberos.kerb.server.preauth;
 
+import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.server.KdcContext;
 import org.apache.kerby.kerberos.kerb.server.preauth.builtin.EncTsPreauth;
 import org.apache.kerby.kerberos.kerb.server.preauth.builtin.TgtPreauth;
+import org.apache.kerby.kerberos.kerb.server.preauth.token.TokenPreauth;
 import org.apache.kerby.kerberos.kerb.server.request.KdcRequest;
-import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaData;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaDataEntry;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaDataType;
@@ -50,6 +51,9 @@ public class PreauthHandler {
 
         preauth = new TgtPreauth();
         preauths.add(preauth);
+
+        preauth = new TokenPreauth();
+        preauths.add(preauth);
     }
 
     /**
@@ -120,4 +124,13 @@ public class PreauthHandler {
             preauth.destroy();
         }
     }
+
+    public static boolean isToken(PaData paData) {
+        for (PaDataEntry paEntry : paData.getElements()) {
+            if (paEntry.getPaDataType() == PaDataType.TOKEN_REQUEST) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/token/TokenPreauth.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/token/TokenPreauth.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/token/TokenPreauth.java
new file mode 100644
index 0000000..49fbd40
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/preauth/token/TokenPreauth.java
@@ -0,0 +1,79 @@
+/**
+ *  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.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.server.preauth.token;
+
+import org.apache.kerby.kerberos.kerb.KrbCodec;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.KrbRuntime;
+import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
+import org.apache.kerby.kerberos.kerb.preauth.PluginRequestContext;
+import org.apache.kerby.kerberos.kerb.preauth.token.TokenPreauthMeta;
+import org.apache.kerby.kerberos.kerb.provider.TokenDecoder;
+import org.apache.kerby.kerberos.kerb.server.preauth.AbstractPreauthPlugin;
+import org.apache.kerby.kerberos.kerb.server.request.AsRequest;
+import org.apache.kerby.kerberos.kerb.server.request.KdcRequest;
+import org.apache.kerby.kerberos.kerb.spec.base.AuthToken;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptedData;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
+import org.apache.kerby.kerberos.kerb.spec.base.KrbToken;
+import org.apache.kerby.kerberos.kerb.spec.pa.PaDataEntry;
+import org.apache.kerby.kerberos.kerb.spec.pa.PaDataType;
+import org.apache.kerby.kerberos.kerb.spec.pa.token.PaTokenRequest;
+
+import java.io.IOException;
+
+public class TokenPreauth extends AbstractPreauthPlugin {
+
+    public TokenPreauth() {
+        super(new TokenPreauthMeta());
+    }
+
+    @Override
+    public boolean verify(KdcRequest kdcRequest, PluginRequestContext requestContext,
+                          PaDataEntry paData) throws KrbException {
+
+        if (paData.getPaDataType() == PaDataType.TOKEN_REQUEST) {
+            EncryptedData encData = KrbCodec.decode(paData.getPaDataValue(), EncryptedData.class);
+            EncryptionKey clientKey = kdcRequest.getArmorKey();
+            kdcRequest.setClientKey(clientKey);
+
+            PaTokenRequest paTokenRequest = EncryptionUtil.unseal(encData, clientKey,
+                KeyUsage.PA_TOKEN, PaTokenRequest.class);
+
+            KrbToken token = paTokenRequest.getToken();
+
+            TokenDecoder tokenDecoder = KrbRuntime.getTokenProvider().createTokenDecoder();
+            AuthToken authToken = null;
+            try {
+                authToken = tokenDecoder.decodeFromBytes(token.getTokenValue());
+            } catch (IOException e) {
+                throw new KrbException("Decoding failed", e);
+            }
+
+            AsRequest asRequest = (AsRequest) kdcRequest;
+            asRequest.setToken(authToken);
+
+            return true;
+        } else {
+            return false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
index c402926..33a5507 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
@@ -24,8 +24,19 @@ import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
 import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
 import org.apache.kerby.kerberos.kerb.server.KdcContext;
 import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
-import org.apache.kerby.kerberos.kerb.spec.base.*;
-import org.apache.kerby.kerberos.kerb.spec.kdc.*;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptedData;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
+import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
+import org.apache.kerby.kerberos.kerb.spec.base.LastReq;
+import org.apache.kerby.kerberos.kerb.spec.base.LastReqEntry;
+import org.apache.kerby.kerberos.kerb.spec.base.LastReqType;
+import org.apache.kerby.kerberos.kerb.spec.base.PrincipalName;
+import org.apache.kerby.kerberos.kerb.spec.kdc.AsRep;
+import org.apache.kerby.kerberos.kerb.spec.kdc.AsReq;
+import org.apache.kerby.kerberos.kerb.spec.kdc.EncAsRepPart;
+import org.apache.kerby.kerberos.kerb.spec.kdc.EncKdcRepPart;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcReq;
 import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
 import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlag;
 
@@ -37,16 +48,26 @@ public class AsRequest extends KdcRequest {
 
     @Override
     protected void checkClient() throws KrbException {
-        KdcReq request = getKdcReq();
 
-        PrincipalName clientPrincipal = request.getReqBody().getCname();
+        KdcReq request = getKdcReq();
+        PrincipalName clientPrincipal;
+        if (isToken()) {
+            clientPrincipal = new PrincipalName(getToken().getSubject());
+        } else {
+            clientPrincipal = request.getReqBody().getCname();
+        }
         String clientRealm = request.getReqBody().getRealm();
         if (clientRealm == null || clientRealm.isEmpty()) {
             clientRealm = getKdcContext().getKdcRealm();
         }
         clientPrincipal.setRealm(clientRealm);
-
-        KrbIdentity clientEntry = getEntry(clientPrincipal.getName());
+        KrbIdentity clientEntry;
+        if (isToken()) {
+            clientEntry = new KrbIdentity(clientPrincipal.getName());
+            clientEntry.setExpireTime(new KerberosTime(getToken().getExpiredTime().getTime()));
+        } else {
+            clientEntry = getEntry(clientPrincipal.getName());
+        }
         setClientEntry(clientEntry);
 
         for (EncryptionType encType : request.getReqBody().getEtypes()) {
@@ -67,20 +88,21 @@ public class AsRequest extends KdcRequest {
 
     @Override
     protected void makeReply() throws KrbException {
+
         Ticket ticket = getTicket();
 
         AsRep reply = new AsRep();
+        reply.setTicket(ticket);
 
         reply.setCname(getClientEntry().getPrincipal());
         reply.setCrealm(getKdcContext().getKdcRealm());
-        reply.setTicket(ticket);
 
         EncKdcRepPart encKdcRepPart = makeEncKdcRepPart();
         reply.setEncPart(encKdcRepPart);
 
         EncryptionKey clientKey = getClientKey();
         EncryptedData encryptedData = EncryptionUtil.seal(encKdcRepPart,
-                clientKey, KeyUsage.AS_REP_ENCPART);
+            clientKey, KeyUsage.AS_REP_ENCPART);
         reply.setEncryptedEncPart(encryptedData);
 
         setReply(reply);

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
index 82cce78..abbdc02 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
@@ -19,7 +19,11 @@
  */
 package org.apache.kerby.kerberos.kerb.server.request;
 
-import org.apache.kerby.kerberos.kerb.*;
+import org.apache.kerby.kerberos.kerb.KrbCodec;
+import org.apache.kerby.kerberos.kerb.KrbConstant;
+import org.apache.kerby.kerberos.kerb.KrbErrorCode;
+import org.apache.kerby.kerberos.kerb.KrbErrorException;
+import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
 import org.apache.kerby.kerberos.kerb.common.KrbUtil;
 import org.apache.kerby.kerberos.kerb.crypto.CheckSumHandler;
@@ -32,7 +36,20 @@ import org.apache.kerby.kerberos.kerb.server.preauth.PreauthContext;
 import org.apache.kerby.kerberos.kerb.server.preauth.PreauthHandler;
 import org.apache.kerby.kerberos.kerb.spec.ap.ApReq;
 import org.apache.kerby.kerberos.kerb.spec.ap.Authenticator;
-import org.apache.kerby.kerberos.kerb.spec.base.*;
+import org.apache.kerby.kerberos.kerb.spec.base.AuthToken;
+import org.apache.kerby.kerberos.kerb.spec.base.CheckSum;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptedData;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
+import org.apache.kerby.kerberos.kerb.spec.base.EtypeInfo;
+import org.apache.kerby.kerberos.kerb.spec.base.EtypeInfo2;
+import org.apache.kerby.kerberos.kerb.spec.base.EtypeInfo2Entry;
+import org.apache.kerby.kerberos.kerb.spec.base.EtypeInfoEntry;
+import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
+import org.apache.kerby.kerberos.kerb.spec.base.KrbError;
+import org.apache.kerby.kerberos.kerb.spec.base.KrbMessage;
+import org.apache.kerby.kerberos.kerb.spec.base.MethodData;
+import org.apache.kerby.kerberos.kerb.spec.base.PrincipalName;
 import org.apache.kerby.kerberos.kerb.spec.fast.ArmorType;
 import org.apache.kerby.kerberos.kerb.spec.fast.KrbFastArmor;
 import org.apache.kerby.kerberos.kerb.spec.fast.KrbFastArmoredReq;
@@ -70,6 +87,8 @@ public abstract class KdcRequest {
     private KdcFastContext fastContext;
     private PrincipalName serverPrincipal;
     private byte[] innerBodyout;
+    private AuthToken token;
+    private Boolean isToken = false;
 
     public KdcRequest(KdcReq kdcReq, KdcContext kdcContext) {
         this.kdcReq = kdcReq;
@@ -94,15 +113,28 @@ public abstract class KdcRequest {
 
     public void process() throws KrbException {
         checkVersion();
+        checkTgsEntry();
         kdcFindFast();
-        checkClient();
-        checkServer();
-        preauth();
+        if (PreauthHandler.isToken(getKdcReq().getPaData())) {
+            isToken = true;
+            preauth();
+            checkClient();
+            checkServer();
+        } else {
+            checkClient();
+            checkServer();
+            preauth();
+        }
         authenticate();
         issueTicket();
         makeReply();
     }
 
+    private void checkTgsEntry() throws KrbException {
+        KrbIdentity tgsEntry = getEntry(getTgsPrincipal().getName());
+        setTgsEntry(tgsEntry);
+    }
+
     private void kdcFindFast() throws KrbException {
 
         PaData paData = getKdcReq().getPaData();
@@ -264,16 +296,18 @@ public abstract class KdcRequest {
     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 we can not get the client entry, maybe it is token preauth, ignore it.
+        if (entry != null) {
+            if (entry.isDisabled()) {
+                throw new KrbException(KrbErrorCode.KDC_ERR_CLIENT_REVOKED);
+            }
 
-        if (entry.getExpireTime().lessThan(new Date().getTime())) {
-            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);
+            }
         }
     }
 
@@ -282,6 +316,10 @@ public abstract class KdcRequest {
     protected void preauth() throws KrbException {
         KdcReq request = getKdcReq();
 
+        if (!kdcContext.getConfig().isAllowTokenPreauth()) {
+            return;
+        }
+
         PaData preAuthData = request.getPaData();
 
         if (preauthContext.isPreauthRequired()) {
@@ -331,9 +369,6 @@ public abstract class KdcRequest {
     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()) {
@@ -407,9 +442,9 @@ public abstract class KdcRequest {
         }
 
         if (entry == null) {
-            throw new KrbException(krbErrorCode);
+            // Maybe it is the token preauth, now we ignore check client entry.
+            return null;
         }
-
         return entry;
     }
 
@@ -432,4 +467,16 @@ public abstract class KdcRequest {
     public byte[] getInnerBodyout() {
         return innerBodyout;
     }
+
+    public boolean isToken() {
+        return isToken;
+    }
+
+    public void setToken(AuthToken authToken) {
+        this.token = authToken;
+    }
+
+    public AuthToken getToken() {
+        return token;
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
index 34e21c2..9025e97 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
@@ -19,19 +19,32 @@
  */
 package org.apache.kerby.kerberos.kerb.server.request;
 
-import org.apache.kerby.kerberos.kerb.KrbErrorCode;
 import org.apache.kerby.kerberos.kerb.KrbCodec;
+import org.apache.kerby.kerberos.kerb.KrbConstant;
+import org.apache.kerby.kerberos.kerb.KrbErrorCode;
+import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
 import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
 import org.apache.kerby.kerberos.kerb.server.KdcContext;
-import org.apache.kerby.kerberos.kerb.KrbConstant;
-import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
 import org.apache.kerby.kerberos.kerb.spec.ap.ApOption;
 import org.apache.kerby.kerberos.kerb.spec.ap.ApReq;
 import org.apache.kerby.kerberos.kerb.spec.ap.Authenticator;
-import org.apache.kerby.kerberos.kerb.spec.base.*;
-import org.apache.kerby.kerberos.kerb.spec.kdc.*;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptedData;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
+import org.apache.kerby.kerberos.kerb.spec.base.HostAddresses;
+import org.apache.kerby.kerberos.kerb.spec.base.KeyUsage;
+import org.apache.kerby.kerberos.kerb.spec.base.KrbMessageType;
+import org.apache.kerby.kerberos.kerb.spec.base.LastReq;
+import org.apache.kerby.kerberos.kerb.spec.base.LastReqEntry;
+import org.apache.kerby.kerberos.kerb.spec.base.LastReqType;
+import org.apache.kerby.kerberos.kerb.spec.base.PrincipalName;
+import org.apache.kerby.kerberos.kerb.spec.kdc.EncKdcRepPart;
+import org.apache.kerby.kerberos.kerb.spec.kdc.EncTgsRepPart;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcReq;
+import org.apache.kerby.kerberos.kerb.spec.kdc.TgsRep;
+import org.apache.kerby.kerberos.kerb.spec.kdc.TgsReq;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaDataEntry;
 import org.apache.kerby.kerberos.kerb.spec.ticket.EncTicketPart;
 import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
@@ -156,7 +169,11 @@ public class TgsRequest extends KdcRequest {
 
         TgsRep reply = new TgsRep();
 
-        reply.setCname(getClientEntry().getPrincipal());
+        if (getClientEntry() == null) {
+            reply.setCname(ticket.getEncPart().getCname());
+        } else {
+            reply.setCname(getClientEntry().getPrincipal());
+        }
         reply.setCrealm(getKdcContext().getKdcRealm());
         reply.setTicket(ticket);
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TickertIssuer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TickertIssuer.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TickertIssuer.java
index 372bd02..8dce0d3 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TickertIssuer.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TickertIssuer.java
@@ -65,7 +65,7 @@ public abstract class TickertIssuer {
         EncryptionKey encryptionKey = getTicketEncryptionKey();
 
         EncryptedData encryptedData = EncryptionUtil.seal(encTicketPart,
-                encryptionKey, KeyUsage.KDC_REP_TICKET);
+            encryptionKey, KeyUsage.KDC_REP_TICKET);
         issuedTicket.setEncryptedEncPart(encryptedData);
         issuedTicket.setEncPart(encTicketPart);
 
@@ -201,7 +201,11 @@ public abstract class TickertIssuer {
     }
 
     protected PrincipalName getclientPrincipal() {
-        return getKdcReq().getReqBody().getCname();
+        if (kdcRequest.isToken()) {
+            return new PrincipalName(kdcRequest.getToken().getSubject());
+        } else {
+            return getKdcReq().getReqBody().getCname();
+        }
     }
 
     protected PrincipalName getServerPrincipal() {

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f46f994f/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Credential.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Credential.java b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Credential.java
index cd33c92..ed1c033 100644
--- a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Credential.java
+++ b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Credential.java
@@ -32,8 +32,7 @@ import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlags;
 
 import java.io.IOException;
 
-public class Credential
-{
+public class Credential {
     private static String CONF_REALM = "X-CACHECONF:";
 
     private PrincipalName clientName;