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/07/30 08:24:48 UTC

[41/50] [abbrv] directory-kerby git commit: DIRKRB-374 An end to end test for the token mechanism.

DIRKRB-374 An end to end test for the token 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/f12cd554
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/f12cd554
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/f12cd554

Branch: refs/heads/pkinit-support
Commit: f12cd5540eab5f445588d50285f615f7f985d64d
Parents: ea31281
Author: plusplusjiajia <ji...@intel.com>
Authored: Fri Jul 24 14:13:14 2015 +0800
Committer: plusplusjiajia <ji...@intel.com>
Committed: Fri Jul 24 14:13:14 2015 +0800

----------------------------------------------------------------------
 kerby-kerb/integration-test/pom.xml             |   5 +
 .../test/jaas/TokenAuthLoginModule.java         | 250 +++++++++++++++++++
 .../kerb/integration/test/jaas/TokenCache.java  | 113 +++++++++
 .../integration/test/jaas/TokenJaasKrbUtil.java | 141 +++++++++++
 .../integration/test/TokenLoginTestBase.java    | 140 +++++++++++
 .../TokenLoginTestWithTokenPreauthDisabled.java |  54 ++++
 .../TokenLoginTestWithTokenPreauthEnabled.java  |  43 ++++
 .../kerby/kerberos/kerb/client/KrbConfig.java   |   6 +-
 .../kerberos/kerb/server/LoginTestBase.java     |   6 +-
 .../kerb/server/preauth/token/TokenPreauth.java |   3 +
 .../kerb/server/request/KdcRequest.java         |   6 +-
 .../kerby/kerberos/kerb/client/Krb5Conf.java    |  11 +-
 .../kerb-simplekdc/src/main/resources/krb5.conf |   5 +-
 .../src/main/resources/krb5_udp.conf            |   5 +-
 14 files changed, 773 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/integration-test/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/pom.xml b/kerby-kerb/integration-test/pom.xml
index 7483c28..36fcff6 100644
--- a/kerby-kerb/integration-test/pom.xml
+++ b/kerby-kerb/integration-test/pom.xml
@@ -44,5 +44,10 @@
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>token-provider</artifactId>
+      <version>${project.version}</version>
+    </dependency>
   </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenAuthLoginModule.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenAuthLoginModule.java b/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenAuthLoginModule.java
new file mode 100644
index 0000000..0470a21
--- /dev/null
+++ b/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenAuthLoginModule.java
@@ -0,0 +1,250 @@
+/**
+ *  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.integration.test.jaas;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.KrbRuntime;
+import org.apache.kerby.kerberos.kerb.client.Krb5Conf;
+import org.apache.kerby.kerberos.kerb.client.KrbClient;
+import org.apache.kerby.kerberos.kerb.client.KrbConfig;
+import org.apache.kerby.kerberos.kerb.provider.TokenDecoder;
+import org.apache.kerby.kerberos.kerb.spec.base.AuthToken;
+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.ticket.TgtTicket;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This <code>LoginModule</code> authenticates users using token.
+ * tokenStr: token-string
+ * tokenCache: token-cache-file
+ * armorCache: armor-cache-file
+ */
+public class TokenAuthLoginModule implements LoginModule {
+    private static final Logger LOG = LoggerFactory.getLogger(TokenAuthLoginModule.class);
+
+    /** initial state*/
+    private Subject subject;
+
+    /** configurable option*/
+    private String tokenCacheName = null;
+
+    /** the authentication status*/
+    private boolean succeeded = false;
+    private boolean commitSucceeded = false;
+
+    private String princName = null;
+    private String tokenStr = null;
+    private AuthToken authToken = null;
+    KrbToken krbToken = null;
+    private File armorCache;
+    private File cCache;
+    public static final String PRINCIPAL = "principal";
+    public static final String TOKEN = "token";
+    public static final String TOKEN_CACHE = "tokenCache";
+    public static final String ARMOR_CACHE = "armorCache";
+    public static final String CREDENTIAL_CACHE = "credentialCache";
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void initialize(Subject subject, CallbackHandler callbackHandler,
+                           Map<String, ?> sharedState, Map<String, ?> options) {
+
+        this.subject = subject;
+        /** initialize any configured options*/
+        princName = (String)options.get(PRINCIPAL);
+        tokenStr = (String) options.get(TOKEN);
+        tokenCacheName = (String) options.get(TOKEN_CACHE);
+        armorCache = new File((String) options.get(ARMOR_CACHE));
+        cCache = new File((String) options.get(CREDENTIAL_CACHE));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean login() throws LoginException {
+        validateConfiguration();
+
+        succeeded = tokenLogin();
+        return succeeded;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean commit() throws LoginException {
+
+        if (succeeded == false) {
+            return false;
+        } else {
+            subject.getPublicCredentials().add(krbToken);
+        }
+        commitSucceeded = true;
+        LOG.info("Commit Succeeded \n");
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean abort() throws LoginException {
+        if (succeeded == false) {
+            return false;
+        } else if (succeeded == true && commitSucceeded == false) {
+            // login succeeded but overall authentication failed
+            succeeded = false;
+        } else {
+            // overall authentication succeeded and commit succeeded,
+            // but someone else's commit failed
+            logout();
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean logout() throws LoginException {
+        LOG.info("\t\t[TokenAuthLoginModule]: Entering logout");
+
+        if (subject.isReadOnly()) {
+            throw new LoginException("Subject is Readonly");
+        }
+
+        subject.getPrincipals().remove(princName);
+        // Let us remove all Kerberos credentials stored in the Subject
+        Iterator<Object> it = subject.getPrivateCredentials().iterator();
+        while (it.hasNext()) {
+            Object o = it.next();
+            if (o instanceof KrbToken) {
+                it.remove();
+            }
+        }
+
+        cleanup();
+
+        succeeded = false;
+        commitSucceeded = false;
+
+        LOG.info("\t\t[TokenAuthLoginModule]: logged out Subject");
+        return true;
+    }
+
+    private void validateConfiguration() throws LoginException {
+
+        String error = "";
+        if (tokenStr == null && tokenCacheName == null) {
+            error = "useToken is specified but no token or token cache is provided";
+        } else if (tokenStr != null && tokenCacheName != null) {
+            error = "either token or token cache should be provided but not both";
+        }
+
+        if (!error.isEmpty()) {
+            throw new LoginException(error);
+        }
+    }
+
+    private boolean tokenLogin() throws LoginException {
+        if (tokenStr == null) {
+            tokenStr = TokenCache.readToken(tokenCacheName);
+            if (tokenStr == null) {
+                throw new LoginException("No valid token was found in token cache: " + tokenCacheName);
+            }
+        }
+        TokenDecoder tokenDecoder = KrbRuntime.getTokenProvider().createTokenDecoder();
+        try {
+            authToken = tokenDecoder.decodeFromString(tokenStr);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        krbToken = new KrbToken(authToken, TokenFormat.JWT);
+        KrbClient krbClient = null;
+        try {
+            File confFile = new File(System.getProperty(Krb5Conf.KRB5_CONF));
+            KrbConfig krbConfig = new KrbConfig();
+            krbConfig.addIniConfig(confFile);
+            krbClient = new KrbClient(krbConfig);
+            krbClient.init();
+        } catch (KrbException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        TgtTicket tgtTicket = null;
+        try {
+            tgtTicket = krbClient.requestTgtWithToken(krbToken, armorCache.getAbsolutePath());
+        } catch (KrbException e) {
+            throwWith("Failed to do login with token: " + tokenStr, e);
+            return false;
+        }
+
+        try {
+            cCache = makeTgtCache();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        try {
+            krbClient.storeTicket(tgtTicket, cCache);
+        } catch (KrbException e) {
+            e.printStackTrace();
+        }
+        return true;
+    }
+
+    private File makeTgtCache() throws IOException {
+
+        if (!cCache.exists() && !cCache.createNewFile()) {
+            throw new IOException("Failed to create tgtcache file "
+                    + cCache.getAbsolutePath());
+        }
+        cCache.setExecutable(false);
+        cCache.setReadable(true);
+        cCache.setWritable(true);
+        return cCache;
+    }
+
+    private void cleanup() {
+        if (cCache != null && cCache.exists()) {
+            cCache.delete();
+        }
+    }
+
+    private void throwWith(String error, Exception cause) throws LoginException {
+        LoginException le = new LoginException(error);
+        le.initCause(cause);
+        throw le;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenCache.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenCache.java b/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenCache.java
new file mode 100644
index 0000000..010793c
--- /dev/null
+++ b/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenCache.java
@@ -0,0 +1,113 @@
+/**
+ *  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.integration.test.jaas;
+
+
+import org.apache.commons.io.output.FileWriterWithEncoding;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+import java.io.*;
+import java.nio.charset.Charset;
+
+/**
+ * This class provides APIs for converting token cache file with token string.
+ */
+public class TokenCache {
+    private static final String DEFAULT_TOKEN_CACHE_PATH = ".tokenauth";
+    private static final String TOKEN_CACHE_FILE = ".tokenauth.token";
+
+    /**
+     * Obtain token string from token cache file.
+     *
+     * @param tokenCacheFile The file stored token
+     * @return Token string
+     */
+    public static String readToken(String tokenCacheFile) {
+        File cacheFile;
+
+        if (tokenCacheFile != null && !tokenCacheFile.isEmpty()) {
+            cacheFile = new File(tokenCacheFile);
+            if (!cacheFile.exists()) {
+                throw new RuntimeException("Invalid token cache specified: " + tokenCacheFile);
+            }
+        } else {
+            cacheFile = getDefaultTokenCache();
+            if (!cacheFile.exists()) {
+                throw new RuntimeException("No token cache available by default");
+            }
+        }
+
+        String token = null;
+        try {
+            BufferedReader reader = new BufferedReader(
+                    new InputStreamReader(new FileInputStream(cacheFile), Charset.forName("UTF-8")));
+            String line = reader.readLine();
+            reader.close();
+            if (line != null) {
+                token = line;
+            }
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+
+        return token;
+    }
+
+    /**
+     * Write the token string to token cache file.
+     *
+     * @param token The token string
+     */
+    public static void writeToken(String token) {
+        File cacheFile = getDefaultTokenCache();
+
+        try {
+            Writer writer = new FileWriterWithEncoding(cacheFile, Charset.forName("UTF-8"));
+            writer.write(token);
+            writer.flush();
+            writer.close();
+            // sets read-write permissions to owner only
+            cacheFile.setReadable(false, false);
+            cacheFile.setReadable(true, true);
+            if (!cacheFile.setWritable(true, true)) {
+                throw new KrbException("Cache file is not readable.");
+            }
+        } catch (IOException ioe) {
+            // if case of any error we just delete the cache, if user-only
+            // write permissions are not properly set a security exception
+            // is thrown and the file will be deleted.
+            if (cacheFile.delete()) {
+                System.err.println("Cache file is deleted.");
+            }
+        } catch (KrbException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Get the default token cache.
+     *
+     * @return  The default token cache
+     */
+    public static File getDefaultTokenCache() {
+        String homeDir = System.getProperty("user.home", DEFAULT_TOKEN_CACHE_PATH);
+        return new File(homeDir, TOKEN_CACHE_FILE);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenJaasKrbUtil.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenJaasKrbUtil.java b/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenJaasKrbUtil.java
new file mode 100644
index 0000000..b79fef0
--- /dev/null
+++ b/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/jaas/TokenJaasKrbUtil.java
@@ -0,0 +1,141 @@
+/**
+ *  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.integration.test.jaas;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import java.io.File;
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * JAAS utilities for token login.
+ */
+public class TokenJaasKrbUtil {
+
+    /**
+     * Login using token cache.
+     *
+     * @param principal The client principal name
+     * @param tokenCache the token cache for login
+     * @param armorCache the armor cache for fast preauth
+     * @param ccache The file to store the tgt ticket
+     * @return the authenticated Subject
+     */
+    public static Subject loginUsingToken(
+            String principal, File tokenCache, File armorCache, File ccache)
+            throws LoginException {
+        Set<Principal> principals = new HashSet<Principal>();
+        principals.add(new KerberosPrincipal(principal));
+
+        Subject subject = new Subject(false, principals,
+                new HashSet<Object>(), new HashSet<Object>());
+        Configuration conf = useTokenCache(principal, tokenCache, armorCache, ccache);
+        String confName = "TokenCacheConf";
+        LoginContext loginContext = new LoginContext(confName, subject, null, conf);
+        loginContext.login();
+        return loginContext.getSubject();
+    }
+
+    /**
+     * Login using token string.
+     *
+     * @param principal The client principal name
+     * @param tokenStr the token string for login
+     * @param armorCache the armor cache for fast preauth
+     * @param ccache The file to store the tgt ticket
+     * @return the authenticated Subject
+     */
+    public static Subject loginUsingToken(
+            String principal, String tokenStr, File armorCache, File ccache)
+            throws LoginException {
+        Set<Principal> principals = new HashSet<Principal>();
+        principals.add(new KerberosPrincipal(principal));
+
+        Subject subject = new Subject(false, principals,
+                new HashSet<Object>(), new HashSet<Object>());
+        Configuration conf = useTokenStr(principal, tokenStr, armorCache, ccache);
+        String confName = "TokenStrConf";
+        LoginContext loginContext = new LoginContext(confName, subject, null, conf);
+        loginContext.login();
+        return loginContext.getSubject();
+    }
+
+    private static Configuration useTokenCache(String principal, File tokenCache,
+                                              File armorCache, File tgtCache) {
+        return new TokenJaasConf(principal, tokenCache, armorCache, tgtCache);
+    }
+
+    private static Configuration useTokenStr(String principal, String tokenStr,
+                                            File armorCache, File tgtCache) {
+        return new TokenJaasConf(principal, tokenStr, armorCache, tgtCache);
+    }
+
+    /**
+     * Token Jaas config.
+     */
+    static class TokenJaasConf extends Configuration {
+        private String principal;
+        private File tokenCache;
+        private String tokenStr;
+        private File armorCache;
+        private File ccache;
+
+        public TokenJaasConf(String principal, File tokenCache, File armorCache, File ccache) {
+            this.principal = principal;
+            this.tokenCache = tokenCache;
+            this.armorCache = armorCache;
+            this.ccache = ccache;
+        }
+
+        public TokenJaasConf(String principal, String tokenStr, File armorCache, File ccache) {
+            this.principal = principal;
+            this.tokenStr = tokenStr;
+            this.armorCache = armorCache;
+            this.ccache = ccache;
+        }
+
+        @Override
+        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+            Map<String, String> options = new HashMap<String, String>();
+            options.put(TokenAuthLoginModule.PRINCIPAL, principal);
+            if (tokenCache != null) {
+                options.put(TokenAuthLoginModule.TOKEN_CACHE, tokenCache.getAbsolutePath());
+            } else if (tokenStr != null) {
+                options.put(TokenAuthLoginModule.TOKEN, tokenStr);
+            }
+            options.put(TokenAuthLoginModule.ARMOR_CACHE, armorCache.getAbsolutePath());
+            options.put(TokenAuthLoginModule.CREDENTIAL_CACHE, ccache.getAbsolutePath());
+
+            return new AppConfigurationEntry[]{
+                    new AppConfigurationEntry(
+                            "org.apache.kerby.kerberos.kerb.integration.test.jaas.TokenAuthLoginModule",
+                            AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+                            options)};
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestBase.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestBase.java b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestBase.java
new file mode 100644
index 0000000..ec7205f
--- /dev/null
+++ b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestBase.java
@@ -0,0 +1,140 @@
+/**
+ *  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.integration.test;
+
+import org.apache.kerby.kerberos.kerb.KrbRuntime;
+import org.apache.kerby.kerberos.kerb.integration.test.jaas.TokenCache;
+import org.apache.kerby.kerberos.kerb.integration.test.jaas.TokenJaasKrbUtil;
+import org.apache.kerby.kerberos.kerb.provider.TokenEncoder;
+import org.apache.kerby.kerberos.kerb.server.KdcConfigKey;
+import org.apache.kerby.kerberos.kerb.server.LoginTestBase;
+import org.apache.kerby.kerberos.kerb.spec.base.AuthToken;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TgtTicket;
+import org.apache.kerby.kerberos.provider.token.JwtTokenProvider;
+import org.junit.Before;
+
+import javax.security.auth.Subject;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class TokenLoginTestBase extends LoginTestBase {
+
+    private File tokenCache;
+    private File armorCache;
+    private File tgtCache;
+
+    static final String GROUP = "sales-group";
+    static final String ROLE = "ADMIN";
+
+    static {
+        KrbRuntime.setTokenProvider(new JwtTokenProvider());
+    }
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        armorCache = new File(getTestDir(), "armorcache.cc");
+        tgtCache = new File(getTestDir(), "tgtcache.cc");
+    }
+
+    @Override
+    protected void configKdcSeverAndClient() {
+        super.configKdcSeverAndClient();
+        getKdcServer().getKdcConfig().setBoolean(KdcConfigKey.ALLOW_TOKEN_PREAUTH,
+                isTokenPreauthAllowed());
+    }
+
+    protected Boolean isTokenPreauthAllowed() {
+        return true;
+    }
+
+    private String createTokenAndArmorCache() throws Exception {
+
+        TokenEncoder tokenEncoder = null;
+        try {
+            tokenEncoder = KrbRuntime.getTokenProvider().createTokenEncoder();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        AuthToken token = issueToken(getClientPrincipal());
+        String tokenStr = tokenEncoder.encodeAsString(token);
+        TokenCache.writeToken(tokenStr);
+        System.out.println("Issued token: " + tokenStr);
+        tokenCache = TokenCache.getDefaultTokenCache();
+
+        TgtTicket tgt = getKrbClient().requestTgtWithPassword(getClientPrincipal(),
+                getClientPassword());
+        getKrbClient().storeTicket(tgt, armorCache);
+
+        return tokenStr;
+    }
+
+    private AuthToken issueToken(String principal) {
+        AuthToken authToken = KrbRuntime.getTokenProvider().createTokenFactory().createToken();
+
+        String iss = "token-service";
+        authToken.setIssuer(iss);
+
+        String sub = principal;
+        authToken.setSubject(sub);
+
+        authToken.addAttribute("group", GROUP);
+
+        authToken.addAttribute("role", ROLE);
+
+        List<String> aud = new ArrayList<String>();
+        aud.add("krb5kdc-with-token-extension");
+        authToken.setAudiences(aud);
+
+        // Set expiration in 60 minutes
+        final Date now = new Date(new Date().getTime() / 1000 * 1000);
+        Date exp = new Date(now.getTime() + 1000 * 60 * 60);
+        authToken.setExpirationTime(exp);
+
+        Date nbf = now;
+        authToken.setNotBeforeTime(nbf);
+
+        Date iat = now;
+        authToken.setIssueTime(iat);
+
+        return authToken;
+    }
+
+    private Subject loginClientUsingTokenStr(String tokenStr, File armorCache, File tgtCache) throws Exception {
+        return TokenJaasKrbUtil.loginUsingToken(getClientPrincipal(), tokenStr, armorCache, tgtCache);
+    }
+
+    private Subject loginClientUsingTokenCache(File tokenCache, File armorCache, File tgtCache) throws Exception {
+        return TokenJaasKrbUtil.loginUsingToken(getClientPrincipal(), tokenCache, armorCache, tgtCache);
+    }
+
+    protected void testLoginWithTokenStr() throws Exception {
+        String tokenStr = createTokenAndArmorCache();
+        checkSubject(loginClientUsingTokenStr(tokenStr, armorCache, tgtCache));
+    }
+
+    protected void testLoginWithTokenCache() throws Exception {
+        createTokenAndArmorCache();
+        checkSubject(loginClientUsingTokenCache(tokenCache, armorCache, tgtCache));
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestWithTokenPreauthDisabled.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestWithTokenPreauthDisabled.java b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestWithTokenPreauthDisabled.java
new file mode 100644
index 0000000..857d6f2
--- /dev/null
+++ b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestWithTokenPreauthDisabled.java
@@ -0,0 +1,54 @@
+/**
+ *  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.integration.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test login with token when token preauth is not allowed by kdc.
+ */
+public class TokenLoginTestWithTokenPreauthDisabled extends TokenLoginTestBase {
+
+    @Override
+    protected Boolean isTokenPreauthAllowed() {
+        return false;
+    }
+
+    @Test
+    public void testLoginWithTokenStr() throws Exception {
+        try {
+            super.testLoginWithTokenStr();
+            Assert.fail("Exception should have been thrown");
+        } catch (Exception e) {
+          //expects exception
+        }
+    }
+
+    @Test
+    public void testLoginWithTokenCache() throws Exception {
+        try {
+            super.testLoginWithTokenCache();
+            Assert.fail("Exception should have been thrown");
+        } catch (Exception e) {
+          //expects exception
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestWithTokenPreauthEnabled.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestWithTokenPreauthEnabled.java b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestWithTokenPreauthEnabled.java
new file mode 100644
index 0000000..ffa720e
--- /dev/null
+++ b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenLoginTestWithTokenPreauthEnabled.java
@@ -0,0 +1,43 @@
+/**
+ *  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.integration.test;
+
+import org.junit.Test;
+
+/**
+ * Test login with token when token preauth is allowed by kdc.
+ */
+public class TokenLoginTestWithTokenPreauthEnabled extends TokenLoginTestBase {
+
+    @Override
+    protected Boolean isTokenPreauthAllowed() {
+        return true;
+    }
+
+    @Test
+    public void testLoginWithTokenStr() throws Exception {
+        super.testLoginWithTokenStr();
+    }
+
+    @Test
+    public void testLoginWithTokenCache() throws Exception {
+        super.testLoginWithTokenCache();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbConfig.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbConfig.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbConfig.java
index fdb95d7..919126b 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbConfig.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbConfig.java
@@ -50,7 +50,7 @@ public class KrbConfig extends Conf {
         Integer kdcPort = KrbConfHelper.getIntUnderSection(this,
                 KrbConfigKey.KDC_PORT);
         if (kdcPort != null) {
-            return kdcPort.shortValue();
+            return kdcPort.intValue();
         }
         return -1;
     }
@@ -63,7 +63,7 @@ public class KrbConfig extends Conf {
         Integer kdcPort = KrbConfHelper.getIntUnderSection(this,
                 KrbConfigKey.KDC_TCP_PORT);
         if (kdcPort != null && kdcPort > 0) {
-            return kdcPort.shortValue();
+            return kdcPort.intValue();
         }
         return getKdcPort();
     }
@@ -93,7 +93,7 @@ public class KrbConfig extends Conf {
         Integer kdcPort = KrbConfHelper.getIntUnderSection(this,
                 KrbConfigKey.KDC_UDP_PORT);
         if (kdcPort != null && kdcPort > 0) {
-            return kdcPort.shortValue();
+            return kdcPort.intValue();
         }
         return getKdcPort();
     }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/LoginTestBase.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/LoginTestBase.java b/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/LoginTestBase.java
index 7c2f564..18628ad 100644
--- a/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/LoginTestBase.java
+++ b/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/LoginTestBase.java
@@ -6,16 +6,16 @@
  *  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;
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/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
index 44bddf9..969b8d2 100644
--- 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
@@ -53,6 +53,9 @@ public class TokenPreauth extends AbstractPreauthPlugin {
     public boolean verify(KdcRequest kdcRequest, PluginRequestContext requestContext,
                           PaDataEntry paData) throws KrbException {
 
+        if(!kdcRequest.getKdcContext().getConfig().isAllowTokenPreauth()) {
+            throw new KrbException("Token preauth is not allowed.");
+        }
         if (paData.getPaDataType() == PaDataType.TOKEN_REQUEST) {
             EncryptedData encData = KrbCodec.decode(paData.getPaDataValue(), EncryptedData.class);
             EncryptionKey clientKey = kdcRequest.getArmorKey();

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/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 424acd4..3581aac 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
@@ -339,13 +339,9 @@ public abstract class KdcRequest {
     protected void preauth() throws KrbException {
         KdcReq request = getKdcReq();
 
-        if (!kdcContext.getConfig().isAllowTokenPreauth()) {
-            return;
-        }
-
         PaData preAuthData = request.getPaData();
 
-        if (preauthContext.isPreauthRequired()) {
+        if (isPreauthRequired()) {
             if (preAuthData == null || preAuthData.isEmpty()) {
                 LOG.info("The preauth data is empty.");
                 KrbError krbError = makePreAuthenticationError(kdcContext, request,

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/kerb-simplekdc/src/main/java/org/apache/kerby/kerberos/kerb/client/Krb5Conf.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-simplekdc/src/main/java/org/apache/kerby/kerberos/kerb/client/Krb5Conf.java b/kerby-kerb/kerb-simplekdc/src/main/java/org/apache/kerby/kerberos/kerb/client/Krb5Conf.java
index 6b5fcd0..ab9c8c9 100644
--- a/kerby-kerb/kerb-simplekdc/src/main/java/org/apache/kerby/kerberos/kerb/client/Krb5Conf.java
+++ b/kerby-kerb/kerb-simplekdc/src/main/java/org/apache/kerby/kerberos/kerb/client/Krb5Conf.java
@@ -12,7 +12,7 @@ import java.io.InputStream;
  * Generate krb5 file using given kdc server settings.
  */
 public class Krb5Conf {
-    private static final String KRB5_CONF = "java.security.krb5.conf";
+    public static final String KRB5_CONF = "java.security.krb5.conf";
     private static final String KRB5_CONF_FILE = "krb5.conf";
     private SimpleKdcServer kdcServer;
 
@@ -39,9 +39,16 @@ public class Krb5Conf {
 
         int kdcPort = setting.allowUdp() ? setting.getKdcUdpPort()
                 : setting.getKdcTcpPort();
-        content = content.replaceAll("_PORT_",
+        content = content.replaceAll("_KDC_PORT_",
                 String.valueOf(kdcPort));
 
+        if(setting.allowTcp()) {
+            content = content.replaceAll("#_KDC_TCP_PORT_", "kdc_tcp_port = " + setting.getKdcTcpPort());
+        }
+        if(setting.allowUdp()) {
+            content = content.replaceAll("#_KDC_UDP_PORT_", "kdc_udp_port = " + setting.getKdcUdpPort());
+        }
+
         int udpLimit = setting.allowUdp() ? 4096 : 1;
         content = content.replaceAll("_UDP_LIMIT_", String.valueOf(udpLimit));
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/kerb-simplekdc/src/main/resources/krb5.conf
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-simplekdc/src/main/resources/krb5.conf b/kerby-kerb/kerb-simplekdc/src/main/resources/krb5.conf
index 511587c..4c3b297 100644
--- a/kerby-kerb/kerb-simplekdc/src/main/resources/krb5.conf
+++ b/kerby-kerb/kerb-simplekdc/src/main/resources/krb5.conf
@@ -1,8 +1,11 @@
 [libdefaults]
+    kdc_realm = _REALM_
     default_realm = _REALM_
     udp_preference_limit = _UDP_LIMIT_
+    #_KDC_TCP_PORT_
+    #_KDC_UDP_PORT_
 
 [realms]
     _REALM_ = {
-        kdc = localhost:_PORT_
+        kdc = localhost:_KDC_PORT_
     }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/f12cd554/kerby-kerb/kerb-simplekdc/src/main/resources/krb5_udp.conf
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-simplekdc/src/main/resources/krb5_udp.conf b/kerby-kerb/kerb-simplekdc/src/main/resources/krb5_udp.conf
index 511587c..4c3b297 100644
--- a/kerby-kerb/kerb-simplekdc/src/main/resources/krb5_udp.conf
+++ b/kerby-kerb/kerb-simplekdc/src/main/resources/krb5_udp.conf
@@ -1,8 +1,11 @@
 [libdefaults]
+    kdc_realm = _REALM_
     default_realm = _REALM_
     udp_preference_limit = _UDP_LIMIT_
+    #_KDC_TCP_PORT_
+    #_KDC_UDP_PORT_
 
 [realms]
     _REALM_ = {
-        kdc = localhost:_PORT_
+        kdc = localhost:_KDC_PORT_
     }
\ No newline at end of file