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/09/05 11:09:44 UTC

directory-kerby git commit: DIRKRB-651 - Add support to send a JWT AccessToken via the GSS API

Repository: directory-kerby
Updated Branches:
  refs/heads/trunk c4c43ced6 -> 515b3f2f8


DIRKRB-651 - Add support to send a JWT AccessToken via the GSS API


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

Branch: refs/heads/trunk
Commit: 515b3f2f86f6d5a20714a04bedca5757fa832280
Parents: c4c43ce
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Tue Sep 5 12:09:03 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Tue Sep 5 12:09:03 2017 +0100

----------------------------------------------------------------------
 .../integration/test/KerbyTokenAppTest.java     | 126 +++++++++++++++++++
 .../kerb/integration/test/TokenAppTest.java     |  88 +++++++++++++
 .../kerberos/kerb/gss/impl/GssContext.java      |   4 +-
 .../kerberos/kerb/gss/impl/GssInitCred.java     |  19 ++-
 .../kerby/kerberos/kerb/gss/impl/GssUtil.java   |  54 ++++++--
 5 files changed, 275 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/515b3f2f/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyTokenAppTest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyTokenAppTest.java b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyTokenAppTest.java
new file mode 100644
index 0000000..b0033f4
--- /dev/null
+++ b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyTokenAppTest.java
@@ -0,0 +1,126 @@
+/**
+ *  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 java.io.InputStream;
+import java.security.PrivateKey;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.interfaces.RSAPrivateKey;
+import java.util.Collections;
+
+import javax.security.auth.Subject;
+
+import org.apache.kerby.kerberos.kerb.KrbRuntime;
+import org.apache.kerby.kerberos.kerb.common.PrivateKeyReader;
+import org.apache.kerby.kerberos.kerb.gss.KerbyGssProvider;
+import org.apache.kerby.kerberos.kerb.integration.test.gss.GssAppClient;
+import org.apache.kerby.kerberos.kerb.integration.test.gss.GssAppServer;
+import org.apache.kerby.kerberos.kerb.provider.TokenEncoder;
+import org.apache.kerby.kerberos.kerb.type.base.AuthToken;
+import org.apache.kerby.kerberos.kerb.type.base.KrbToken;
+import org.apache.kerby.kerberos.kerb.type.base.TokenFormat;
+import org.apache.kerby.kerberos.provider.token.JwtTokenEncoder;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.assertTrue;
+
+public class KerbyTokenAppTest extends TokenAppTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(KerbyGssAppTest.class);
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        Provider provider = new KerbyGssProvider();
+        java.security.Security.insertProviderAt(provider, 1);
+        super.setUp();
+    }
+
+    // Here the client is sending a JWT token to the service as an "access token", to be
+    // inserted into the AuthorizationData part of the service ticket.
+    @Test
+    public void testJwtAccessToken() throws Exception {
+        runAppClientWithToken(createAppClient());
+    }
+
+    private void runAppClientWithToken(final AppClient appClient) throws Exception {
+        Subject subject = loginClientUsingPassword();
+
+        // Get an AuthToken
+        AuthToken authToken = issueToken(getClientPrincipal());
+        authToken.isAcToken(true);
+        authToken.isIdToken(false);
+        authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
+        KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
+
+        // Sign it
+        try (InputStream is = this.getClass().getResource("/private_key.pem").openStream()) {
+            PrivateKey signKey = PrivateKeyReader.loadPrivateKey(is);
+            krbToken.setTokenValue(signToken(authToken, signKey));
+        }
+
+        // Add KrbToken to the private creds
+        subject.getPrivateCredentials().add(krbToken);
+
+        Subject.doAs(subject, new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                try {
+                    appClient.run();
+                } catch (Exception ex) {
+                    LOG.error(ex.toString());
+                }
+                return null;
+            }
+        });
+
+        assertTrue("Client successfully connected and authenticated to server",
+                   appClient.isTestOK());
+    }
+
+    private byte[] signToken(AuthToken authToken, PrivateKey signKey) throws Exception {
+        TokenEncoder tokenEncoder = KrbRuntime.getTokenProvider().createTokenEncoder();
+        assertTrue(tokenEncoder instanceof JwtTokenEncoder);
+
+        ((JwtTokenEncoder) tokenEncoder).setSignKey((RSAPrivateKey) signKey);
+        return tokenEncoder.encodeAsBytes(authToken);
+    }
+
+    @Override
+    protected AppServer createAppServer() throws Exception {
+        return new GssAppServer(new String[] {
+            String.valueOf(getServerPort()),
+            getServerPrincipal()
+        });
+    }
+
+    private AppClient createAppClient() throws Exception {
+        return new GssAppClient(new String[] {
+            getHostname(),
+            String.valueOf(getServerPort()),
+                getClientPrincipal(),
+                getServerPrincipal()
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/515b3f2f/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenAppTest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenAppTest.java b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenAppTest.java
new file mode 100644
index 0000000..55298f9
--- /dev/null
+++ b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/TokenAppTest.java
@@ -0,0 +1,88 @@
+/**
+ *  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.util.NetworkUtil;
+import org.junit.Assert;
+import org.junit.Before;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.auth.Subject;
+import java.security.PrivilegedAction;
+
+public abstract class TokenAppTest extends TokenLoginTestBase {
+    private static final Logger LOG = LoggerFactory.getLogger(TokenAppTest.class);
+    private int serverPort;
+    protected AppServer appServer;
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        serverPort = NetworkUtil.getServerPort();
+
+        setupAppServer();
+    }
+
+    protected int getServerPort() {
+        return serverPort;
+    }
+
+    protected void setupAppServer() throws Exception {
+        Subject subject = loginServiceUsingKeytab();
+        Subject.doAs(subject, new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                try {
+                    appServer = createAppServer();
+                    appServer.start();
+                } catch (Exception ex) {
+                    LOG.error(ex.toString());
+                }
+
+                return null;
+            }
+        });
+    }
+
+    protected abstract AppServer createAppServer() throws Exception;
+
+    protected void runAppClient(final AppClient appClient) throws Exception {
+        Subject subject = loginClientUsingTicketCache();
+        Subject.doAs(subject, new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                try {
+                    appClient.run();
+                } catch (Exception ex) {
+                    LOG.error(ex.toString());
+                }
+                return null;
+            }
+        });
+
+        Assert.assertTrue("Client successfully connected and authenticated to server",
+                appClient.isTestOK());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/515b3f2f/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssContext.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssContext.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssContext.java
index 138bdd2..3da77d2 100644
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssContext.java
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssContext.java
@@ -278,7 +278,9 @@ public class GssContext implements GSSContextSpi {
             sgtTicket = GssUtil.getSgtCredentialFromContext(caller, clientPrincipal.getName(), serviceName);
 
             if (sgtTicket == null) {
-                sgtTicket = GssUtil.applySgtCredential(((GssInitCred) myCred).getKerberosTicket(), serviceName);
+                sgtTicket = GssUtil.applySgtCredential(((GssInitCred) myCred).getKerberosTicket(),
+                                                       ((GssInitCred) myCred).getKrbToken(),
+                                                       serviceName);
 
                 // add this service credential to context
                 final KerberosTicket ticket =

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/515b3f2f/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssInitCred.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssInitCred.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssInitCred.java
index 225e581..aa41718 100644
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssInitCred.java
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssInitCred.java
@@ -19,32 +19,41 @@
  */
 package org.apache.kerby.kerberos.kerb.gss.impl;
 
+import org.apache.kerby.kerberos.kerb.type.base.KrbToken;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.GSSName;
 
 import sun.security.jgss.GSSCaller;
 
+import java.util.Set;
+
 import javax.security.auth.kerberos.KerberosTicket;
 
 public final class GssInitCred extends GssCredElement {
 
     private KerberosTicket ticket;
+    private KrbToken krbToken;
 
-    private GssInitCred(GSSCaller caller, GssNameElement name, KerberosTicket ticket, int lifeTime) {
+    private GssInitCred(GSSCaller caller, GssNameElement name,
+                        KerberosTicket ticket, KrbToken krbToken, int lifeTime) {
         super(caller, name);
         this.ticket = ticket;
         this.initLifeTime = lifeTime;
+        this.krbToken = krbToken;
     }
 
     public static GssInitCred getInstance(GSSCaller caller, GssNameElement name, int lifeTime) throws GSSException {
+        Set<KrbToken> krbTokens = CredUtils.getContextCredentials(KrbToken.class);
+        KrbToken krbToken = krbTokens != null && !krbTokens.isEmpty() ? krbTokens.iterator().next() : null;
+
         if (name == null) {
             KerberosTicket ticket = CredUtils.getKerberosTicketFromContext(caller, null, null);
             GssNameElement clientName = GssNameElement.getInstance(ticket.getClient().getName(), GSSName.NT_USER_NAME);
-            return new GssInitCred(caller, clientName, ticket, lifeTime);
+            return new GssInitCred(caller, clientName, ticket, krbToken, lifeTime);
         }
 
         KerberosTicket ticket = CredUtils.getKerberosTicketFromContext(caller, name.getPrincipalName().getName(), null);
-        return new GssInitCred(caller, name, ticket, lifeTime);
+        return new GssInitCred(caller, name, ticket, krbToken, lifeTime);
     }
 
     public boolean isInitiatorCredential() throws GSSException {
@@ -58,4 +67,8 @@ public final class GssInitCred extends GssCredElement {
     public KerberosTicket getKerberosTicket() {
         return ticket;
     }
+
+    public KrbToken getKrbToken() {
+        return krbToken;
+    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/515b3f2f/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java
index 099c79b..ca3c509 100644
--- a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssUtil.java
@@ -21,12 +21,14 @@ package org.apache.kerby.kerberos.kerb.gss.impl;
 
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.client.KrbClientBase;
+import org.apache.kerby.kerberos.kerb.client.KrbTokenClient;
 import org.apache.kerby.kerberos.kerb.type.KerberosTime;
 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.EncryptionKey;
 import org.apache.kerby.kerberos.kerb.type.base.HostAddress;
 import org.apache.kerby.kerberos.kerb.type.base.HostAddresses;
+import org.apache.kerby.kerberos.kerb.type.base.KrbToken;
 import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
 import org.apache.kerby.kerberos.kerb.type.kdc.EncAsRepPart;
 import org.apache.kerby.kerberos.kerb.type.kdc.EncKdcRepPart;
@@ -217,22 +219,37 @@ public class GssUtil {
     /**
      *  Apply SgtTicket by sending TGS_REQ to KDC
      * @param ticket
+     * @param krbToken
      * @param service
      * @return
      */
-    public static SgtTicket applySgtCredential(KerberosTicket ticket, String service) throws GSSException {
+    public static SgtTicket applySgtCredential(KerberosTicket ticket, KrbToken krbToken,
+                                               String service) throws GSSException {
         TgtTicket tgt = getTgtTicketFromKerberosTicket(ticket);
-        return applySgtCredential(tgt, service);
+        if (krbToken == null) {
+            return applySgtCredential(tgt, service);
+        }
+
+        return applySgtCredential(tgt, krbToken, service);
     }
 
     public static SgtTicket applySgtCredential(TgtTicket tgt, String server) throws GSSException {
         KrbClientBase client = getKrbClient();
 
-        SgtTicket sgt = null;
         try {
             client.init();
-            sgt = client.requestSgt(tgt, server);
-            return sgt;
+            return client.requestSgt(tgt, server);
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
+        }
+    }
+
+    public static SgtTicket applySgtCredential(TgtTicket tgt, KrbToken krbToken, String server) throws GSSException {
+        KrbTokenClient client = getKrbTokenClient();
+
+        try {
+            client.init();
+            return client.requestSgt(krbToken, server, tgt);
         } catch (KrbException e) {
             throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
         }
@@ -302,21 +319,34 @@ public class GssUtil {
     }
 
     public static KrbClientBase getKrbClient() {
-        KrbClientBase client;
         try {
             String systemProperty = getSystemProperty("java.security.krb5.conf");
             if (systemProperty != null) {
                 File confSpecified = new File(systemProperty);
                 if (confSpecified.exists()) {
-                    client = new KrbClientBase(confSpecified);
-                } else {
-                    client = new KrbClientBase();   // get configure file from environment variable or default path
+                    return new KrbClientBase(confSpecified);
+                }
+            }
+
+            // get configuration file from environment variable or default path
+            return new KrbClientBase();
+        } catch (KrbException e) {
+            return null;
+        }
+    }
+
+    public static KrbTokenClient getKrbTokenClient() {
+        try {
+            String systemProperty = getSystemProperty("java.security.krb5.conf");
+            if (systemProperty != null) {
+                File confSpecified = new File(systemProperty);
+                if (confSpecified.exists()) {
+                    return new KrbTokenClient(confSpecified);
                 }
-            } else {
-                client = new KrbClientBase();
             }
 
-            return client;
+            // get configuration file from environment variable or default path
+            return new KrbTokenClient();
         } catch (KrbException e) {
             return null;
         }