You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by co...@apache.org on 2017/07/05 15:27:46 UTC

[1/3] directory-kerby git commit: DIRKRB-Put claims from the JWT access token into the authorization data of the ticket

Repository: directory-kerby
Updated Branches:
  refs/heads/trunk 8b990ad26 -> 0e3234bca


DIRKRB-Put claims from the JWT access token into the authorization data of the ticket


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

Branch: refs/heads/trunk
Commit: 44c142be568960e88241990b33cab586022658c5
Parents: 8b990ad
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Wed Jul 5 15:36:06 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Wed Jul 5 15:36:06 2017 +0100

----------------------------------------------------------------------
 .../kerb/type/ad/AuthorizationType.java         | 73 +++++++++++---------
 .../backend/AbstractIdentityBackend.java        | 27 +++++++-
 2 files changed, 66 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/44c142be/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/type/ad/AuthorizationType.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/type/ad/AuthorizationType.java b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/type/ad/AuthorizationType.java
index e6c40c4..80fa207 100644
--- a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/type/ad/AuthorizationType.java
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/type/ad/AuthorizationType.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. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.kerby.kerberos.kerb.type.ad;
 
@@ -23,7 +23,7 @@ import org.apache.kerby.asn1.EnumType;
 
 /**
  * The various AuthorizationType values, as defined in RFC 4120 and RFC 1510.
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
 public enum AuthorizationType implements EnumType {
@@ -36,7 +36,7 @@ public enum AuthorizationType implements EnumType {
      * Constant for the "if relevant" authorization type.
      *
      * RFC 4120
-     * 
+     *
      * AD elements encapsulated within the if-relevant element are intended for
      * interpretation only by application servers that understand the particular
      * ad-type of the embedded element. Application servers that do not
@@ -51,16 +51,16 @@ public enum AuthorizationType implements EnumType {
      * Constant for the "intended for server" authorization type.
      *
      * RFC 4120
-     * 
+     *
      * AD-INTENDED-FOR-SERVER SEQUENCE { intended-server[0] SEQUENCE OF
      * PrincipalName elements[1] AuthorizationData }
-     * 
+     *
      * AD elements encapsulated within the intended-for-server element may be
      * ignored if the application server is not in the list of principal names
      * of intended servers. Further, a KDC issuing a ticket for an application
      * server can remove this element if the application server is not in the
      * list of intended servers.
-     * 
+     *
      * Application servers should check for their principal name in the
      * intended-server field of this element. If their principal name is not
      * found, this element should be ignored. If found, then the encapsulated
@@ -75,16 +75,16 @@ public enum AuthorizationType implements EnumType {
      * Constant for the  "intended for application class" authorization type.
      *
      * RFC 4120
-     * 
+     *
      * AD-INTENDED-FOR-APPLICATION-CLASS SEQUENCE {
      * intended-application-class[0] SEQUENCE OF GeneralString elements[1]
      * AuthorizationData } AD elements
-     * 
+     *
      * encapsulated within the intended-for-application-class element may be
      * ignored if the application server is not in one of the named classes of
      * application servers. Examples of application server classes include
      * "FILESYSTEM", and other kinds of servers.
-     * 
+     *
      * This element and the elements it encapsulates may be safely ignored by
      * applications, application servers, and KDCs that do not implement this
      * element.
@@ -95,11 +95,11 @@ public enum AuthorizationType implements EnumType {
      * Constant for the "kdc issued" authorization type.
      *
      * RFC 4120
-     * 
+     *
      * AD-KDCIssued SEQUENCE { ad-checksum[0] Checksum, i-realm[1] Realm
      * OPTIONAL, i-sname[2] PrincipalName OPTIONAL, elements[3]
      * AuthorizationData. }
-     * 
+     *
      * ad-checksum A checksum over the elements field using a cryptographic
      * checksum method that is identical to the checksum used to protect the
      * ticket itself (i.e. using the same hash function and the same encryption
@@ -110,13 +110,13 @@ public enum AuthorizationType implements EnumType {
      * issuing principal and it allows this KDC to notify the application server
      * of the validity of those elements. elements A sequence of authorization
      * data elements issued by the KDC.
-     * 
+     *
      * The KDC-issued ad-data field is intended to provide a means for Kerberos
      * principal credentials to embed within themselves privilege attributes and
      * other mechanisms for positive authorization, amplifying the privileges of
      * the principal beyond what can be done using a credentials without such an
      * a-data element.
-     * 
+     *
      * This can not be provided without this element because the definition of
      * the authorization-data field allows elements to be added at will by the
      * bearer of a TGT at the time that they request service tickets and
@@ -129,7 +129,7 @@ public enum AuthorizationType implements EnumType {
      * Constant for the "and/or" authorization type.
      *
      * RFC 4120
-     * 
+     *
      * When restrictive AD elements encapsulated within the and-or element are
      * encountered, only the number specified in condition-count of the
      * encapsulated conditions must be met in order to satisfy this element.
@@ -145,9 +145,9 @@ public enum AuthorizationType implements EnumType {
      * Constant for the "mandatory ticket extensions" authorization type.
      *
      * RFC 4120
-     * 
+     *
      * AD-Mandatory-Ticket-Extensions Checksum
-     * 
+     *
      * An authorization data element of type mandatory-ticket-extensions
      * specifies a collision-proof checksum using the same hash algorithm used
      * to protect the integrity of the ticket itself. This checksum will be
@@ -164,9 +164,9 @@ public enum AuthorizationType implements EnumType {
      * Constant for the "in ticket extensions" authorization type.
      *
      * RFC 4120
-     * 
+     *
      * AD-IN-Ticket-Extensions Checksum
-     * 
+     *
      * An authorization data element of type in-ticket-extensions specifies a
      * collision-proof checksum using the same hash algorithm used to protect
      * the integrity of the ticket itself. This checksum is calculated over a
@@ -187,9 +187,9 @@ public enum AuthorizationType implements EnumType {
      * Constant for the "mandatory-for-kdc" authorization type.
      *
      * RFC 4120
-     * 
+     *
      * AD-MANDATORY-FOR-KDC ::= AuthorizationData
-     * 
+     *
      * AD elements encapsulated within the mandatory-for-kdc element are to be
      * interpreted by the KDC. KDCs that do not understand the type of an
      * element embedded within the mandatory-for-kdc element MUST reject the
@@ -201,22 +201,22 @@ public enum AuthorizationType implements EnumType {
      * Constant for the "initial-verified-cas" authorization type.
      *
      * RFC 4556
-     * 
+     *
      * AD-INITIAL-VERIFIED-CAS ::= SEQUENCE OF ExternalPrincipalIdentifier --
      * Identifies the certification path with which -- the client certificate
      * was validated. -- Each ExternalPrincipalIdentifier identifies a CA -- or
      * a CA certificate (thereby its public key).
-     * 
+     *
      * The AD-INITIAL-VERIFIED-CAS structure identifies the certification path
      * with which the client certificate was validated. Each
      * ExternalPrincipalIdentifier (as defined in Section 3.2.1) in the AD-
      * INITIAL-VERIFIED-CAS structure identifies a CA or a CA certificate
      * (thereby its public key).
-     * 
+     *
      * Note that the syntax for the AD-INITIAL-VERIFIED-CAS authorization data
      * does permit empty SEQUENCEs to be encoded. Such empty sequences may only
      * be used if the KDC itself vouches for the user's certificate.
-     * 
+     *
      * The AS wraps any AD-INITIAL-VERIFIED-CAS data in AD-IF-RELEVANT
      * containers if the list of CAs satisfies the AS' realm's local policy
      * (this corresponds to the TRANSITED-POLICY-CHECKED ticket flag [RFC4120]).
@@ -225,7 +225,7 @@ public enum AuthorizationType implements EnumType {
      * of CAs satisfies the local KDC's realm's policy, the TGS MAY wrap the
      * data into the AD-IF-RELEVANT container; otherwise, it MAY unwrap the
      * authorization data out of the AD-IF-RELEVANT container.
-     * 
+     *
      * Application servers that understand this authorization data type SHOULD
      * apply local policy to determine whether a given ticket bearing such a
      * type *not* contained within an AD-IF-RELEVANT container is acceptable.
@@ -234,7 +234,7 @@ public enum AuthorizationType implements EnumType {
      * data type is contained within an AD-IF- RELEVANT container, AP servers
      * MAY apply local policy to determine whether the authorization data is
      * acceptable.
-     * 
+     *
      * ExternalPrincipalIdentifier ::= SEQUENCE { subjectName [0] IMPLICIT OCTET
      * STRING OPTIONAL, -- Contains a PKIX type Name encoded according to --
      * [RFC3280]. -- Identifies the certificate subject by the -- distinguished
@@ -287,7 +287,7 @@ public enum AuthorizationType implements EnumType {
      * authorization type.
      *
      * RFC 4120
-     * 
+     *
      * See: Microsoft standard documents MS-PAC and MS-KILE.
      */
     AD_WIN2K_PAC(128),
@@ -300,8 +300,15 @@ public enum AuthorizationType implements EnumType {
     AD_ETYPE_NEGOTIATION(129),
 
     /**
+     * Constant for the Authorization Data Type. Note that this is not a standard Type as of yet.
+     *
+     * See the draft spec "Token Pre-Authentication for Kerberos".
+     */
+    AD_TOKEN(256),
+
+    /**
      * Constant for the "Authentication-Indicator" authorization type.
-     * 
+     *
      * RFC 6711 An IANA Registry for Level of Assurance (LoA) Profiles provides
      * the syntax and semantics of LoA profiles.
      *
@@ -313,7 +320,7 @@ public enum AuthorizationType implements EnumType {
     private final int value;
 
     /**
-     * Create a new enum 
+     * Create a new enum
      */
     AuthorizationType(int value) {
         this.value = value;
@@ -337,7 +344,7 @@ public enum AuthorizationType implements EnumType {
 
     /**
      * Get the AuthorizationType associated with a value.
-     * 
+     *
      * @param value The integer value of the AuthorizationType we are looking for
      * @return The associated AuthorizationType, or NULL if not found or if value is null
      */

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/44c142be/kerby-kerb/kerb-identity/src/main/java/org/apache/kerby/kerberos/kerb/identity/backend/AbstractIdentityBackend.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-identity/src/main/java/org/apache/kerby/kerberos/kerb/identity/backend/AbstractIdentityBackend.java b/kerby-kerb/kerb-identity/src/main/java/org/apache/kerby/kerberos/kerb/identity/backend/AbstractIdentityBackend.java
index 7db2a48..d965dc3 100644
--- a/kerby-kerb/kerb-identity/src/main/java/org/apache/kerby/kerberos/kerb/identity/backend/AbstractIdentityBackend.java
+++ b/kerby-kerb/kerb-identity/src/main/java/org/apache/kerby/kerberos/kerb/identity/backend/AbstractIdentityBackend.java
@@ -19,11 +19,19 @@
  */
 package org.apache.kerby.kerberos.kerb.identity.backend;
 
+import java.io.IOException;
+import java.util.Collections;
+
 import org.apache.kerby.config.Configured;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.identity.BatchTrans;
 import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.type.ad.AdToken;
 import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationData;
+import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationDataEntry;
+import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationType;
+import org.apache.kerby.kerberos.kerb.type.base.KrbToken;
+import org.apache.kerby.kerberos.kerb.type.base.TokenFormat;
 import org.apache.kerby.kerberos.kerb.type.kdc.KdcClientRequest;
 import org.apache.kerby.kerberos.kerb.type.ticket.EncTicketPart;
 import org.slf4j.Logger;
@@ -196,7 +204,24 @@ public abstract class AbstractIdentityBackend
      */
     protected AuthorizationData doGetIdentityAuthorizationData(
             KdcClientRequest kdcClientRequest, EncTicketPart encTicketPart)
-            throws KrbException {
+                throws KrbException {
+        if (kdcClientRequest.isToken()) {
+            KrbToken krbToken = new KrbToken(kdcClientRequest.getToken(), TokenFormat.JWT);
+            AdToken adToken = new AdToken();
+            adToken.setToken(krbToken);
+
+            AuthorizationData authzData = new AuthorizationData();
+            AuthorizationDataEntry authzDataEntry = new AuthorizationDataEntry();
+            try {
+                authzDataEntry.setAuthzData(adToken.encode());
+            } catch (IOException e) {
+                throw new KrbException("Error encoding AdToken", e);
+            }
+
+            authzDataEntry.setAuthzType(AuthorizationType.AD_TOKEN);
+            authzData.setElements(Collections.singletonList(authzDataEntry));
+            return authzData;
+        }
         return null;
     }
 


[3/3] directory-kerby git commit: Adding signature tests

Posted by co...@apache.org.
Adding signature tests


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

Branch: refs/heads/trunk
Commit: 0e3234bca25e4a607dca507b9d9e0387e475794d
Parents: 7c89f0a
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Wed Jul 5 16:27:38 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Wed Jul 5 16:27:38 2017 +0100

----------------------------------------------------------------------
 .../kerb/integration/test/JWTTokenTest.java     | 88 +++++++++++++++++---
 1 file changed, 75 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/0e3234bc/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/JWTTokenTest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/JWTTokenTest.java b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/JWTTokenTest.java
index 04ba1d0..aeb0ced 100644
--- a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/JWTTokenTest.java
+++ b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/JWTTokenTest.java
@@ -24,6 +24,8 @@ import static org.junit.Assert.*;
 import java.io.File;
 import java.io.InputStream;
 import java.nio.file.Files;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
 import java.security.PrivateKey;
 import java.security.interfaces.RSAPrivateKey;
 import java.util.Collections;
@@ -89,7 +91,10 @@ public class JWTTokenTest extends TokenLoginTestBase {
         authToken.isIdToken(false);
         authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
         KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
-        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        InputStream is = Files.newInputStream(getSignKeyFile().toPath());
+        PrivateKey signKey = PrivateKeyReader.loadPrivateKey(is);
+        krbToken.setTokenValue(signToken(authToken, signKey));
 
         // Now get a SGT using the JWT
         SgtTicket tkt = tokenClient.requestSgt(krbToken, getServerPrincipal(), cCacheFile.getPath());
@@ -148,7 +153,10 @@ public class JWTTokenTest extends TokenLoginTestBase {
         authToken.isIdToken(false);
         authToken.setAudiences(Collections.singletonList(getServerPrincipal() + "_"));
         KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
-        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        InputStream is = Files.newInputStream(getSignKeyFile().toPath());
+        PrivateKey signKey = PrivateKeyReader.loadPrivateKey(is);
+        krbToken.setTokenValue(signToken(authToken, signKey));
 
         // Now get a SGT using the JWT
         try {
@@ -162,7 +170,6 @@ public class JWTTokenTest extends TokenLoginTestBase {
     }
 
     @org.junit.Test
-    @org.junit.Ignore
     public void accessTokenInvalidSignature() throws Exception {
 
         KrbClient client = getKrbClient();
@@ -194,8 +201,9 @@ public class JWTTokenTest extends TokenLoginTestBase {
         authToken.isIdToken(false);
         authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
         KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
-        File signKeyFile = new File(this.getClass().getResource("/kdckeytest.pem").getPath());
-        krbToken.setTokenValue(signToken(authToken, signKeyFile));
+
+        KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
+        krbToken.setTokenValue(signToken(authToken, keyPair.getPrivate()));
 
         // Now get a SGT using the JWT
         try {
@@ -241,7 +249,10 @@ public class JWTTokenTest extends TokenLoginTestBase {
         authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
         authToken.setIssuer("unknown-issuer");
         KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
-        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        InputStream is = Files.newInputStream(getSignKeyFile().toPath());
+        PrivateKey signKey = PrivateKeyReader.loadPrivateKey(is);
+        krbToken.setTokenValue(signToken(authToken, signKey));
 
         // Now get a SGT using the JWT
         try {
@@ -283,7 +294,10 @@ public class JWTTokenTest extends TokenLoginTestBase {
         // Create a JWT token
         AuthToken authToken = issueToken(getClientPrincipal());
         KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
-        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        InputStream is = Files.newInputStream(getSignKeyFile().toPath());
+        PrivateKey signKey = PrivateKeyReader.loadPrivateKey(is);
+        krbToken.setTokenValue(signToken(authToken, signKey));
 
         // Now get a TGT using the JWT token
         tgt = tokenClient.requestTgt(krbToken, cCacheFile.getPath());
@@ -338,7 +352,10 @@ public class JWTTokenTest extends TokenLoginTestBase {
         AuthToken authToken = issueToken(getClientPrincipal());
         authToken.setAudiences(Collections.singletonList(authToken.getAudiences().get(0) + "_"));
         KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
-        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        InputStream is = Files.newInputStream(getSignKeyFile().toPath());
+        PrivateKey signKey = PrivateKeyReader.loadPrivateKey(is);
+        krbToken.setTokenValue(signToken(authToken, signKey));
 
         // Now get a TGT using the JWT token
         try {
@@ -352,6 +369,51 @@ public class JWTTokenTest extends TokenLoginTestBase {
     }
 
     @org.junit.Test
+    public void identityTokenInvalidSignature() throws Exception {
+
+        KrbClient client = getKrbClient();
+
+        // Get a TGT
+        TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
+        assertNotNull(tgt);
+
+        // Write to cache
+        Credential credential = new Credential(tgt);
+        CredentialCache cCache = new CredentialCache();
+        cCache.addCredential(credential);
+        cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
+
+        File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
+        cCache.store(cCacheFile);
+
+        KrbTokenClient tokenClient = new KrbTokenClient(client);
+
+        tokenClient.setKdcHost(client.getSetting().getKdcHost());
+        tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
+
+        tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
+        tokenClient.init();
+
+        // Create a JWT token
+        AuthToken authToken = issueToken(getClientPrincipal());
+        authToken.setAudiences(Collections.singletonList(authToken.getAudiences().get(0) + "_"));
+        KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
+
+        KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
+        krbToken.setTokenValue(signToken(authToken, keyPair.getPrivate()));
+
+        // Now get a TGT using the JWT token
+        try {
+            tokenClient.requestTgt(krbToken, cCacheFile.getPath());
+            fail("Failure expected on an invalid signature");
+        } catch (KrbException ex) { //NOPMD
+            // expected
+        }
+
+        cCacheFile.delete();
+    }
+
+    @org.junit.Test
     public void identityTokenUnknownIssuer() throws Exception {
 
         KrbClient client = getKrbClient();
@@ -381,7 +443,10 @@ public class JWTTokenTest extends TokenLoginTestBase {
         AuthToken authToken = issueToken(getClientPrincipal());
         authToken.setIssuer("unknown-issuer");
         KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
-        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        InputStream is = Files.newInputStream(getSignKeyFile().toPath());
+        PrivateKey signKey = PrivateKeyReader.loadPrivateKey(is);
+        krbToken.setTokenValue(signToken(authToken, signKey));
 
         // Now get a TGT using the JWT token
         try {
@@ -394,13 +459,10 @@ public class JWTTokenTest extends TokenLoginTestBase {
         cCacheFile.delete();
     }
 
-    private byte[] signToken(AuthToken authToken, File signKeyFile) throws Exception {
+    private byte[] signToken(AuthToken authToken, PrivateKey signKey) throws Exception {
         TokenEncoder tokenEncoder = KrbRuntime.getTokenProvider().createTokenEncoder();
         assertTrue(tokenEncoder instanceof JwtTokenEncoder);
 
-        InputStream is = Files.newInputStream(signKeyFile.toPath());
-        PrivateKey signKey = PrivateKeyReader.loadPrivateKey(is);
-
         ((JwtTokenEncoder) tokenEncoder).setSignKey((RSAPrivateKey) signKey);
         return tokenEncoder.encodeAsBytes(authToken);
     }


[2/3] directory-kerby git commit: DIRKRB-632 - Adding unit tests for identity and access tokens

Posted by co...@apache.org.
DIRKRB-632 - Adding unit tests for identity and access tokens


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

Branch: refs/heads/trunk
Commit: 7c89f0a9d1f9a77730e561e40925447f30498c95
Parents: 44c142b
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Wed Jul 5 16:11:50 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Wed Jul 5 16:11:50 2017 +0100

----------------------------------------------------------------------
 .../kerb/integration/test/JWTTokenTest.java     | 407 +++++++++++++++++++
 .../integration/test/TokenLoginTestBase.java    |   6 +-
 .../kerby/kerberos/kerb/server/KdcTestBase.java |  17 +-
 3 files changed, 423 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/7c89f0a9/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/JWTTokenTest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/JWTTokenTest.java b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/JWTTokenTest.java
new file mode 100644
index 0000000..04ba1d0
--- /dev/null
+++ b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/JWTTokenTest.java
@@ -0,0 +1,407 @@
+/**
+ *  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 static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.security.PrivateKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.util.Collections;
+
+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.client.KrbClient;
+import org.apache.kerby.kerberos.kerb.client.KrbTokenClient;
+import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
+import org.apache.kerby.kerberos.kerb.common.PrivateKeyReader;
+import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
+import org.apache.kerby.kerberos.kerb.provider.TokenEncoder;
+import org.apache.kerby.kerberos.kerb.type.ad.AdToken;
+import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationData;
+import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationDataEntry;
+import org.apache.kerby.kerberos.kerb.type.base.AuthToken;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.KeyUsage;
+import org.apache.kerby.kerberos.kerb.type.base.KrbToken;
+import org.apache.kerby.kerberos.kerb.type.base.TokenFormat;
+import org.apache.kerby.kerberos.kerb.type.ticket.EncTicketPart;
+import org.apache.kerby.kerberos.kerb.type.ticket.SgtTicket;
+import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.apache.kerby.kerberos.kerb.type.ticket.Ticket;
+import org.apache.kerby.kerberos.provider.token.JwtTokenEncoder;
+
+/**
+ * Some tests for JWT tokens using the Kerby client API
+ */
+public class JWTTokenTest extends TokenLoginTestBase {
+
+    @org.junit.Test
+    public void accessToken() throws Exception {
+
+        KrbClient client = getKrbClient();
+
+        // Get a TGT
+        TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
+        assertNotNull(tgt);
+
+        // Write to cache
+        Credential credential = new Credential(tgt);
+        CredentialCache cCache = new CredentialCache();
+        cCache.addCredential(credential);
+        cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
+
+        File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
+        cCache.store(cCacheFile);
+
+        KrbTokenClient tokenClient = new KrbTokenClient(client);
+
+        tokenClient.setKdcHost(client.getSetting().getKdcHost());
+        tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
+
+        tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
+        tokenClient.init();
+
+        // Create a JWT token
+        AuthToken authToken = issueToken(getClientPrincipal());
+        authToken.isAcToken(true);
+        authToken.isIdToken(false);
+        authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
+        KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
+        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        // Now get a SGT using the JWT
+        SgtTicket tkt = tokenClient.requestSgt(krbToken, getServerPrincipal(), cCacheFile.getPath());
+        assertTrue(tkt != null);
+
+        // Decrypt the ticket
+        Ticket ticket = tkt.getTicket();
+        EncryptionKey key = EncryptionHandler.string2Key(getServerPrincipal(), getServerPassword(),
+                                                         ticket.getEncryptedEncPart().getEType());
+
+        EncTicketPart encPart =
+            EncryptionUtil.unseal(ticket.getEncryptedEncPart(),
+                                  key, KeyUsage.KDC_REP_TICKET, EncTicketPart.class);
+
+        // Examine the authorization data
+        AuthorizationData authzData = encPart.getAuthorizationData();
+        assertEquals(1, authzData.getElements().size());
+        AuthorizationDataEntry dataEntry = authzData.getElements().iterator().next();
+        AdToken token = dataEntry.getAuthzDataAs(AdToken.class);
+        KrbToken decodedKrbToken = token.getToken();
+        assertEquals(getClientPrincipal(), decodedKrbToken.getSubject());
+        assertEquals(getServerPrincipal(), decodedKrbToken.getAudiences().get(0));
+
+        cCacheFile.delete();
+    }
+
+    @org.junit.Test
+    public void accessTokenInvalidAudience() throws Exception {
+
+        KrbClient client = getKrbClient();
+
+        // Get a TGT
+        TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
+        assertNotNull(tgt);
+
+        // Write to cache
+        Credential credential = new Credential(tgt);
+        CredentialCache cCache = new CredentialCache();
+        cCache.addCredential(credential);
+        cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
+
+        File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
+        cCache.store(cCacheFile);
+
+        KrbTokenClient tokenClient = new KrbTokenClient(client);
+
+        tokenClient.setKdcHost(client.getSetting().getKdcHost());
+        tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
+
+        tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
+        tokenClient.init();
+
+        // Create a JWT token with an invalid audience
+        AuthToken authToken = issueToken(getClientPrincipal());
+        authToken.isAcToken(true);
+        authToken.isIdToken(false);
+        authToken.setAudiences(Collections.singletonList(getServerPrincipal() + "_"));
+        KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
+        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        // Now get a SGT using the JWT
+        try {
+            tokenClient.requestSgt(krbToken, getServerPrincipal(), cCacheFile.getPath());
+            fail("Failure expected on an invalid audience");
+        } catch (KrbException ex) { //NOPMD
+            // expected
+        }
+
+        cCacheFile.delete();
+    }
+
+    @org.junit.Test
+    @org.junit.Ignore
+    public void accessTokenInvalidSignature() throws Exception {
+
+        KrbClient client = getKrbClient();
+
+        // Get a TGT
+        TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
+        assertNotNull(tgt);
+
+        // Write to cache
+        Credential credential = new Credential(tgt);
+        CredentialCache cCache = new CredentialCache();
+        cCache.addCredential(credential);
+        cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
+
+        File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
+        cCache.store(cCacheFile);
+
+        KrbTokenClient tokenClient = new KrbTokenClient(client);
+
+        tokenClient.setKdcHost(client.getSetting().getKdcHost());
+        tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
+
+        tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
+        tokenClient.init();
+
+        // Create a JWT token with an invalid audience
+        AuthToken authToken = issueToken(getClientPrincipal());
+        authToken.isAcToken(true);
+        authToken.isIdToken(false);
+        authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
+        KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
+        File signKeyFile = new File(this.getClass().getResource("/kdckeytest.pem").getPath());
+        krbToken.setTokenValue(signToken(authToken, signKeyFile));
+
+        // Now get a SGT using the JWT
+        try {
+            tokenClient.requestSgt(krbToken, getServerPrincipal(), cCacheFile.getPath());
+            fail("Failure expected on an invalid signature");
+        } catch (KrbException ex) { //NOPMD
+            // expected
+        }
+
+        cCacheFile.delete();
+    }
+
+    @org.junit.Test
+    public void accessTokenUnknownIssuer() throws Exception {
+
+        KrbClient client = getKrbClient();
+
+        // Get a TGT
+        TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
+        assertNotNull(tgt);
+
+        // Write to cache
+        Credential credential = new Credential(tgt);
+        CredentialCache cCache = new CredentialCache();
+        cCache.addCredential(credential);
+        cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
+
+        File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
+        cCache.store(cCacheFile);
+
+        KrbTokenClient tokenClient = new KrbTokenClient(client);
+
+        tokenClient.setKdcHost(client.getSetting().getKdcHost());
+        tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
+
+        tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
+        tokenClient.init();
+
+        // Create a JWT token with an invalid audience
+        AuthToken authToken = issueToken(getClientPrincipal());
+        authToken.isAcToken(true);
+        authToken.isIdToken(false);
+        authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
+        authToken.setIssuer("unknown-issuer");
+        KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
+        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        // Now get a SGT using the JWT
+        try {
+            tokenClient.requestSgt(krbToken, getServerPrincipal(), cCacheFile.getPath());
+            fail("Failure expected on an unknown issuer");
+        } catch (KrbException ex) { //NOPMD
+            // expected
+        }
+
+        cCacheFile.delete();
+    }
+
+    @org.junit.Test
+    public void identityToken() throws Exception {
+
+        KrbClient client = getKrbClient();
+
+        // Get a TGT
+        TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
+        assertNotNull(tgt);
+
+        // Write to cache
+        Credential credential = new Credential(tgt);
+        CredentialCache cCache = new CredentialCache();
+        cCache.addCredential(credential);
+        cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
+
+        File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
+        cCache.store(cCacheFile);
+
+        KrbTokenClient tokenClient = new KrbTokenClient(client);
+
+        tokenClient.setKdcHost(client.getSetting().getKdcHost());
+        tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
+
+        tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
+        tokenClient.init();
+
+        // Create a JWT token
+        AuthToken authToken = issueToken(getClientPrincipal());
+        KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
+        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        // Now get a TGT using the JWT token
+        tgt = tokenClient.requestTgt(krbToken, cCacheFile.getPath());
+
+        // Now get a SGT using the TGT
+        SgtTicket tkt = tokenClient.requestSgt(tgt, getServerPrincipal());
+        assertTrue(tkt != null);
+
+        // Decrypt the ticket
+        Ticket ticket = tkt.getTicket();
+        EncryptionKey key = EncryptionHandler.string2Key(getServerPrincipal(), getServerPassword(),
+                                                         ticket.getEncryptedEncPart().getEType());
+
+        EncTicketPart encPart =
+            EncryptionUtil.unseal(ticket.getEncryptedEncPart(),
+                                  key, KeyUsage.KDC_REP_TICKET, EncTicketPart.class);
+
+        // Check the authorization data is not present
+        AuthorizationData authzData = encPart.getAuthorizationData();
+        assertNull(authzData);
+
+        cCacheFile.delete();
+    }
+
+    @org.junit.Test
+    public void identityTokenInvalidAudience() throws Exception {
+
+        KrbClient client = getKrbClient();
+
+        // Get a TGT
+        TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
+        assertNotNull(tgt);
+
+        // Write to cache
+        Credential credential = new Credential(tgt);
+        CredentialCache cCache = new CredentialCache();
+        cCache.addCredential(credential);
+        cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
+
+        File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
+        cCache.store(cCacheFile);
+
+        KrbTokenClient tokenClient = new KrbTokenClient(client);
+
+        tokenClient.setKdcHost(client.getSetting().getKdcHost());
+        tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
+
+        tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
+        tokenClient.init();
+
+        // Create a JWT token
+        AuthToken authToken = issueToken(getClientPrincipal());
+        authToken.setAudiences(Collections.singletonList(authToken.getAudiences().get(0) + "_"));
+        KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
+        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        // Now get a TGT using the JWT token
+        try {
+            tokenClient.requestTgt(krbToken, cCacheFile.getPath());
+            fail("Failure expected on an invalid audience");
+        } catch (KrbException ex) { //NOPMD
+            // expected
+        }
+
+        cCacheFile.delete();
+    }
+
+    @org.junit.Test
+    public void identityTokenUnknownIssuer() throws Exception {
+
+        KrbClient client = getKrbClient();
+
+        // Get a TGT
+        TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
+        assertNotNull(tgt);
+
+        // Write to cache
+        Credential credential = new Credential(tgt);
+        CredentialCache cCache = new CredentialCache();
+        cCache.addCredential(credential);
+        cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
+
+        File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
+        cCache.store(cCacheFile);
+
+        KrbTokenClient tokenClient = new KrbTokenClient(client);
+
+        tokenClient.setKdcHost(client.getSetting().getKdcHost());
+        tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
+
+        tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
+        tokenClient.init();
+
+        // Create a JWT token
+        AuthToken authToken = issueToken(getClientPrincipal());
+        authToken.setIssuer("unknown-issuer");
+        KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
+        krbToken.setTokenValue(signToken(authToken, getSignKeyFile()));
+
+        // Now get a TGT using the JWT token
+        try {
+            tokenClient.requestTgt(krbToken, cCacheFile.getPath());
+            fail("Failure expected on an unknown issuer");
+        } catch (KrbException ex) { //NOPMD
+            // expected
+        }
+
+        cCacheFile.delete();
+    }
+
+    private byte[] signToken(AuthToken authToken, File signKeyFile) throws Exception {
+        TokenEncoder tokenEncoder = KrbRuntime.getTokenProvider().createTokenEncoder();
+        assertTrue(tokenEncoder instanceof JwtTokenEncoder);
+
+        InputStream is = Files.newInputStream(signKeyFile.toPath());
+        PrivateKey signKey = PrivateKeyReader.loadPrivateKey(is);
+
+        ((JwtTokenEncoder) tokenEncoder).setSignKey((RSAPrivateKey) signKey);
+        return tokenEncoder.encodeAsBytes(authToken);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/7c89f0a9/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
index 140a81d..044870b 100644
--- 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
@@ -106,7 +106,7 @@ public class TokenLoginTestBase extends LoginTestBase {
         return tokenStr;
     }
 
-    private AuthToken issueToken(String principal) {
+    protected AuthToken issueToken(String principal) {
         AuthToken authToken = KrbRuntime.getTokenProvider().createTokenFactory().createToken();
 
         String iss = "token-service";
@@ -174,4 +174,8 @@ public class TokenLoginTestBase extends LoginTestBase {
     protected File getTGTCache() {
         return tgtCache;
     }
+
+    protected File getSignKeyFile() {
+        return signKeyFile;
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/7c89f0a9/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java b/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
index c4a87be..547db27 100644
--- a/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
+++ b/kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.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. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.kerby.kerberos.kerb.server;
 
@@ -41,6 +41,7 @@ public abstract class KdcTestBase {
     private final String clientPrincipalName = "drankye";
     private final String clientPrincipal =
             clientPrincipalName + "@" + TestKdcServer.KDC_REALM;
+    private final String serverPassword = "654321";
     private final String serverPrincipalName = "test-service";
     private final String serverPrincipal;
 
@@ -112,6 +113,10 @@ public abstract class KdcTestBase {
         return clientPassword;
     }
 
+    protected String getServerPassword() {
+        return serverPassword;
+    }
+
     protected String getServerPrincipal() {
         return serverPrincipal;
     }
@@ -127,7 +132,7 @@ public abstract class KdcTestBase {
     protected boolean allowTcp() {
         return true;
     }
-    
+
     @Before
     public void setUp() throws Exception {
         setUpKdcServer();
@@ -159,7 +164,7 @@ public abstract class KdcTestBase {
     }
 
     protected void createPrincipals() throws KrbException {
-        kdcServer.createPrincipals(serverPrincipal);
+        kdcServer.createPrincipal(serverPrincipal, serverPassword);
         kdcServer.createPrincipal(clientPrincipal, clientPassword);
     }