Merge remote-tracking branch 'asf/trunk' into kadmin-remote
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
index 0d812c9..441fd71 100644
--- 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
@@ -33,10 +33,14 @@
 import org.apache.kerby.kerberos.kerb.type.base.TokenFormat;
 import org.apache.kerby.kerberos.kerb.type.kdc.EncKdcRepPart;
 import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.apache.kerby.kerberos.provider.token.JwtAuthToken;
 import org.apache.kerby.kerberos.provider.token.JwtTokenEncoder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.nimbusds.jwt.JWT;
+import com.nimbusds.jwt.JWTParser;
+
 import javax.security.auth.Subject;
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.kerberos.KerberosPrincipal;
@@ -50,6 +54,7 @@
 import java.security.Principal;
 import java.security.PrivateKey;
 import java.security.interfaces.RSAPrivateKey;
+import java.text.ParseException;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.Map;
@@ -61,6 +66,13 @@
  * armorCache: armor-cache-file
  */
 public class TokenAuthLoginModule implements LoginModule {
+    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";
+    public static final String SIGN_KEY_FILE = "signKeyFile";
+    
     private static final Logger LOG = LoggerFactory.getLogger(TokenAuthLoginModule.class);
 
     /** initial state*/
@@ -76,16 +88,10 @@
     private String princName = null;
     private String tokenStr = null;
     private AuthToken authToken = null;
-    KrbToken krbToken = null;
+    private KrbToken krbToken = null;
     private File armorCache;
     private File cCache;
     private File signKeyFile;
-    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";
-    public static final String SIGN_KEY_FILE = "signKeyFile";
 
     private TgtTicket tgtTicket;
 
@@ -101,9 +107,15 @@
         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));
-        signKeyFile = new File((String) options.get(SIGN_KEY_FILE));
+        if ((String) options.get(ARMOR_CACHE) != null) {
+            armorCache = new File((String) options.get(ARMOR_CACHE));
+        }
+        if ((String) options.get(CREDENTIAL_CACHE) != null) {
+            cCache = new File((String) options.get(CREDENTIAL_CACHE));
+        } 
+        if ((String) options.get(SIGN_KEY_FILE) != null) {
+            signKeyFile = new File((String) options.get(SIGN_KEY_FILE));
+        }
     }
 
     /**
@@ -214,6 +226,15 @@
     }
 
     private void validateConfiguration() throws LoginException {
+        
+        if (armorCache == null) {
+            throw new LoginException("An armor cache must be specified via the armorCache configuration option");
+        }
+        
+        if (cCache == null) {
+            throw new LoginException("A credential cache must be specified via the credentialCache"
+            + " configuration option");
+        }
 
         String error = "";
         if (tokenStr == null && tokenCacheName == null) {
@@ -234,38 +255,55 @@
                 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);
-        TokenEncoder tokenEncoder = KrbRuntime.getTokenProvider().createTokenEncoder();
-
-        if (tokenEncoder instanceof JwtTokenEncoder) {
-            PrivateKey signKey = null;
-            try {
-                FileInputStream fis = new FileInputStream(signKeyFile);
-                signKey = PrivateKeyReader.loadPrivateKey(fis);
-            } catch (FileNotFoundException e) {
-                e.printStackTrace();
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-
-            ((JwtTokenEncoder) tokenEncoder).setSignKey((RSAPrivateKey) signKey);
-        }
 
         krbToken = new KrbToken();
+        
+        // Sign the token.
+        if (signKeyFile != null) {
+            try {
+                TokenDecoder tokenDecoder = KrbRuntime.getTokenProvider().createTokenDecoder();
+                try {
+                    authToken = tokenDecoder.decodeFromString(tokenStr);
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                krbToken = new KrbToken(authToken, TokenFormat.JWT);
+                TokenEncoder tokenEncoder = KrbRuntime.getTokenProvider().createTokenEncoder();
+    
+                if (tokenEncoder instanceof JwtTokenEncoder) {
+                    PrivateKey signKey = null;
+                    try {
+                        FileInputStream fis = new FileInputStream(signKeyFile);
+                        signKey = PrivateKeyReader.loadPrivateKey(fis);
+                    } catch (FileNotFoundException e) {
+                        e.printStackTrace();
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+    
+                    ((JwtTokenEncoder) tokenEncoder).setSignKey((RSAPrivateKey) signKey);
+                }
+                
+                krbToken.setTokenValue(tokenEncoder.encodeAsBytes(authToken));
+            } catch (KrbException e) {
+                throw new RuntimeException("Failed to encode AuthToken", e);
+            }
+        } else {
+            // Otherwise just write out the token (which could be already signed)
+            krbToken.setTokenValue(tokenStr.getBytes());
+            
+            try {
+                JWT jwt = JWTParser.parse(tokenStr);
+                authToken = new JwtAuthToken(jwt.getJWTClaimsSet());
+            } catch (ParseException e) {
+                // Invalid JWT encoding
+                throw new RuntimeException("Failed to parse JWT token string", e);
+            }
+        }
+        
         krbToken.setInnerToken(authToken);
         krbToken.setTokenType();
         krbToken.setTokenFormat(TokenFormat.JWT);
-        try {
-            krbToken.setTokenValue(tokenEncoder.encodeAsBytes(authToken));
-        } catch (KrbException e) {
-            throw new RuntimeException("Failed to encode AuthToken", e);
-        }
 
         KrbClient krbClient = null;
         try {
@@ -279,6 +317,7 @@
         } catch (IOException e) {
             e.printStackTrace();
         }
+        
         KrbTokenClient tokenClient = new KrbTokenClient(krbClient);
         try {
             tgtTicket = tokenClient.requestTgt(krbToken,
diff --git a/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/GssInteropTest.java b/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/GssInteropTest.java
index 7e0d269..cb74b3f 100644
--- a/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/GssInteropTest.java
+++ b/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/GssInteropTest.java
@@ -19,7 +19,6 @@
  */
 package org.apache.kerby.kerberos.kerb.server;
 
-import java.io.ByteArrayOutputStream;
 import java.security.Principal;
 import java.security.PrivilegedExceptionAction;
 import java.util.Set;
@@ -27,12 +26,6 @@
 import javax.security.auth.Subject;
 import javax.security.auth.kerberos.KerberosTicket;
 
-import org.apache.kerby.kerberos.kerb.ccache.CredCacheOutputStream;
-import org.apache.kerby.kerberos.kerb.ccache.Credential;
-import org.apache.kerby.kerberos.kerb.ccache.CredentialCache;
-import org.apache.kerby.kerberos.kerb.client.KrbClient;
-import org.apache.kerby.kerberos.kerb.type.ticket.SgtTicket;
-import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
 import org.ietf.jgss.GSSContext;
 import org.ietf.jgss.GSSCredential;
 import org.ietf.jgss.GSSException;
@@ -71,38 +64,6 @@
         validateServiceTicket(kerberosToken);
     }
     
-    @Test
-    @org.junit.Ignore
-    public void testKerbyClientAndGssService() throws Exception {
-        KrbClient client = getKrbClient();
-        client.init();
-
-        try {
-            // Get a service ticket using Kerby APIs
-            TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
-            Assert.assertTrue(tgt != null);
-
-            SgtTicket tkt = client.requestSgt(tgt, getServerPrincipal());
-            Assert.assertTrue(tkt != null);
-            
-            Credential credential = new Credential(tkt, tgt.getClientPrincipal());
-            CredentialCache cCache = new CredentialCache();
-            cCache.addCredential(credential);
-            cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
-            
-            ByteArrayOutputStream bout = new ByteArrayOutputStream();
-            CredCacheOutputStream os = new CredCacheOutputStream(bout);
-            cCache.store(bout);
-            os.close();
-            
-            // Now validate the ticket using GSS
-            validateServiceTicket(bout.toByteArray());
-        } catch (Exception e) {
-            e.printStackTrace();
-            Assert.fail();
-        }
-    }
-
     private void validateServiceTicket(byte[] ticket) throws Exception {
         Subject serviceSubject = loginServiceUsingKeytab();
         Set<Principal> servicePrincipals = serviceSubject.getPrincipals();
diff --git a/kerby-provider/token-provider/src/main/java/org/apache/kerby/kerberos/provider/token/JwtAuthToken.java b/kerby-provider/token-provider/src/main/java/org/apache/kerby/kerberos/provider/token/JwtAuthToken.java
index e5d92c8..b6e60c4 100644
--- a/kerby-provider/token-provider/src/main/java/org/apache/kerby/kerberos/provider/token/JwtAuthToken.java
+++ b/kerby-provider/token-provider/src/main/java/org/apache/kerby/kerberos/provider/token/JwtAuthToken.java
@@ -40,15 +40,15 @@
     private Boolean isIdToken = true;
     private Boolean isAcToken = false;
 
-    protected JwtAuthToken() {
+    public JwtAuthToken() {
         this(new JWTClaimsSet());
     }
 
-    protected JwtAuthToken(JWTClaimsSet jwtClaims) {
+    public JwtAuthToken(JWTClaimsSet jwtClaims) {
         this.jwtClaims = jwtClaims;
     }
 
-    protected JwtAuthToken(ReadOnlyJWTClaimsSet jwtClaims) {
+    public JwtAuthToken(ReadOnlyJWTClaimsSet jwtClaims) {
         this.jwtClaims = JwtUtil.from(jwtClaims);
     }