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/21 11:27:18 UTC

[31/50] [abbrv] directory-kerby git commit: Refactoring the package and structure

Refactoring the package and structure


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

Branch: refs/heads/gssapi
Commit: 8432c1a81c59e73829c350f328c7956a66d8a809
Parents: de7c8a9
Author: Drankye <dr...@gmail.com>
Authored: Fri Jul 1 17:08:14 2016 +0800
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Fri Jul 21 12:25:51 2017 +0100

----------------------------------------------------------------------
 .../kerb/integration/test/KerbyGssAppTest.java  |   3 +-
 .../kerby/kerberos/kerb/gss/GssMechFactory.java | 149 ++++
 .../kerberos/kerb/gss/KerbyGssProvider.java     |  46 ++
 .../kerby/kerberos/kerb/gss/impl/CredUtils.java |  89 +++
 .../kerberos/kerb/gss/impl/GssAcceptCred.java   |  72 ++
 .../kerberos/kerb/gss/impl/GssContext.java      | 745 +++++++++++++++++++
 .../kerberos/kerb/gss/impl/GssCredElement.java  |  81 ++
 .../kerberos/kerb/gss/impl/GssEncryptor.java    | 388 ++++++++++
 .../kerberos/kerb/gss/impl/GssInitCred.java     |  53 ++
 .../kerberos/kerb/gss/impl/GssNameElement.java  | 135 ++++
 .../kerberos/kerb/gss/impl/GssTokenBase.java    |  59 ++
 .../kerberos/kerb/gss/impl/GssTokenV1.java      | 319 ++++++++
 .../kerberos/kerb/gss/impl/GssTokenV2.java      | 282 +++++++
 .../kerby/kerberos/kerb/gss/impl/GssUtil.java   | 386 ++++++++++
 .../kerberos/kerb/gss/impl/MicTokenV1.java      |  92 +++
 .../kerberos/kerb/gss/impl/MicTokenV2.java      |  94 +++
 .../kerberos/kerb/gss/impl/WrapTokenV1.java     | 196 +++++
 .../kerberos/kerb/gss/impl/WrapTokenV2.java     | 158 ++++
 .../kerberos/kerb/gssapi/KerbyMechFactory.java  | 149 ----
 .../kerby/kerberos/kerb/gssapi/Provider.java    |  46 --
 .../kerberos/kerb/gssapi/krb5/CredUtils.java    |  89 ---
 .../kerb/gssapi/krb5/KerbyAcceptCred.java       |  72 --
 .../kerberos/kerb/gssapi/krb5/KerbyContext.java | 744 ------------------
 .../kerb/gssapi/krb5/KerbyCredElement.java      |  80 --
 .../kerb/gssapi/krb5/KerbyGssEncryptor.java     | 388 ----------
 .../kerb/gssapi/krb5/KerbyGssTokenBase.java     |  59 --
 .../kerb/gssapi/krb5/KerbyGssTokenV1.java       | 319 --------
 .../kerb/gssapi/krb5/KerbyGssTokenV2.java       | 282 -------
 .../kerb/gssapi/krb5/KerbyInitCred.java         |  53 --
 .../kerb/gssapi/krb5/KerbyNameElement.java      | 134 ----
 .../kerberos/kerb/gssapi/krb5/KerbyUtil.java    | 386 ----------
 .../kerberos/kerb/gssapi/krb5/MicTokenV1.java   |  92 ---
 .../kerberos/kerb/gssapi/krb5/MicTokenV2.java   |  94 ---
 .../kerberos/kerb/gssapi/krb5/WrapTokenV1.java  | 196 -----
 .../kerberos/kerb/gssapi/krb5/WrapTokenV2.java  | 158 ----
 35 files changed, 3346 insertions(+), 3342 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyGssAppTest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyGssAppTest.java b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyGssAppTest.java
index d9030df..fbb3f3f 100644
--- a/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyGssAppTest.java
+++ b/kerby-kerb/integration-test/src/test/java/org/apache/kerby/kerberos/kerb/integration/test/KerbyGssAppTest.java
@@ -19,6 +19,7 @@
  */
 package org.apache.kerby.kerberos.kerb.integration.test;
 
+import org.apache.kerby.kerberos.kerb.gss.KerbyGssProvider;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -29,7 +30,7 @@ public class KerbyGssAppTest extends GssAppTest {
     @Before
     @Override
     public void setUp() throws Exception {
-        Provider provider = new org.apache.kerby.kerberos.kerb.gssapi.Provider();
+        Provider provider = new KerbyGssProvider();
         java.security.Security.insertProviderAt(provider, 1);
         super.setUp();
     }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/GssMechFactory.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/GssMechFactory.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/GssMechFactory.java
new file mode 100644
index 0000000..735368b
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/GssMechFactory.java
@@ -0,0 +1,149 @@
+/**
+ *  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.gss;
+
+import org.apache.kerby.kerberos.kerb.gss.impl.GssAcceptCred;
+import org.apache.kerby.kerberos.kerb.gss.impl.GssContext;
+import org.apache.kerby.kerberos.kerb.gss.impl.GssCredElement;
+import org.apache.kerby.kerberos.kerb.gss.impl.GssInitCred;
+import org.apache.kerby.kerberos.kerb.gss.impl.GssNameElement;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSCaller;
+import sun.security.jgss.spi.GSSContextSpi;
+import sun.security.jgss.spi.GSSCredentialSpi;
+import sun.security.jgss.spi.GSSNameSpi;
+import sun.security.jgss.spi.MechanismFactory;
+
+import java.security.Provider;
+
+/**
+ * Kerby Kerberos V5 plugin for JGSS
+ */
+public class GssMechFactory implements MechanismFactory {
+    private static final Provider PROVIDER =
+            new KerbyGssProvider();
+
+    private static final String KRB5_OID_STRING = "1.2.840.113554.1.2.2";
+    private static final Oid KRB5_OID = createOid(KRB5_OID_STRING);
+
+    private static Oid[] nameTypes =
+            new Oid[] {
+                    GSSName.NT_USER_NAME,
+                    GSSName.NT_EXPORT_NAME,
+                    GSSName.NT_HOSTBASED_SERVICE
+            };
+
+    private final GSSCaller caller;
+
+    public Oid getMechanismOid() {
+        return KRB5_OID;
+    }
+
+    public Provider getProvider() {
+        return PROVIDER;
+    }
+
+    public Oid[] getNameTypes() throws GSSException {
+        return nameTypes;
+    }
+
+    public GssMechFactory(GSSCaller caller) {
+        this.caller = caller;
+    }
+
+    public GSSNameSpi getNameElement(String nameStr, Oid nameType)
+            throws GSSException {
+        return GssNameElement.getInstance(nameStr, nameType);
+    }
+
+    public GSSNameSpi getNameElement(byte[] name, Oid nameType)
+            throws GSSException {
+        return GssNameElement.getInstance(name.toString(), nameType);
+    }
+
+    // Used by initiator
+    public GSSContextSpi getMechanismContext(GSSNameSpi peer,
+                                             GSSCredentialSpi myInitiatorCred,
+                                             int lifetime) throws GSSException {
+        if (peer != null && !(peer instanceof GssNameElement)) {
+            peer = GssNameElement.getInstance(peer.toString(), peer.getStringNameType());
+        }
+        if (myInitiatorCred == null) {
+            myInitiatorCred = getCredentialElement(null, lifetime, 0, GSSCredential.INITIATE_ONLY);
+        }
+        return new GssContext(caller, (GssNameElement) peer, (GssInitCred) myInitiatorCred, lifetime);
+    }
+
+    public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
+            throws GSSException {
+        if (myAcceptorCred == null) {
+            myAcceptorCred = getCredentialElement(null, 0,
+                    GSSCredential.INDEFINITE_LIFETIME, GSSCredential.ACCEPT_ONLY);
+        }
+        return new GssContext(caller, (GssAcceptCred) myAcceptorCred);
+    }
+
+    // Reconstruct from previously exported context
+    public GSSContextSpi getMechanismContext(byte[] exportedContext)
+            throws GSSException {
+       return new GssContext(caller, exportedContext);
+    }
+
+    public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
+                                                 int initLifetime,
+                                                 int acceptLifetime,
+                                                 int usage)
+            throws GSSException {
+        if (name != null && !(name instanceof GssNameElement)) {
+            name = GssNameElement.getInstance(name.toString(), name.getStringNameType());
+        }
+
+        GssCredElement credElement;
+
+        if (usage == GSSCredential.INITIATE_ONLY) {
+            credElement = GssInitCred.getInstance(caller, (GssNameElement) name, initLifetime);
+        } else if (usage == GSSCredential.ACCEPT_ONLY) {
+            credElement = GssAcceptCred.getInstance(caller, (GssNameElement) name, acceptLifetime);
+        } else if (usage == GSSCredential.INITIATE_AND_ACCEPT) {
+            throw new GSSException(GSSException.FAILURE, -1, "Unsupported usage mode: INITIATE_AND_ACCEPT");
+        } else {
+            throw new GSSException(GSSException.FAILURE, -1, "Unknown usage mode: " + usage);
+        }
+
+        return credElement;
+    }
+
+    private static Oid createOid(String oidStr) {
+        Oid retVal;
+        try {
+            retVal = new Oid(oidStr);
+        } catch (GSSException e) {
+            retVal = null;
+        }
+        return retVal;
+    }
+
+    public static Oid getOid() {
+        return KRB5_OID;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/KerbyGssProvider.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/KerbyGssProvider.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/KerbyGssProvider.java
new file mode 100644
index 0000000..83c5404
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/KerbyGssProvider.java
@@ -0,0 +1,46 @@
+/**
+ *  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.gss;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Proivder is used to register the implementation of gssapi mechanism into the system
+ */
+public final class KerbyGssProvider extends java.security.Provider {
+    private static final long serialVersionUID = 3787378212107821987L;
+    private static final String INFO = "Kerby Gssapi Provider";
+    private static final String MECHANISM_GSSAPI = "GssApiMechanism.1.2.840.113554.1.2.2";
+    private static final String MECHANISM_GSSAPI_CLASS = "org.apache.kerby.kerberos.kerb.gss.GssMechFactory";
+
+    public KerbyGssProvider() {
+        super("KerbyGssApi", 0.01d, INFO);
+
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+
+                put(MECHANISM_GSSAPI, MECHANISM_GSSAPI_CLASS);
+
+                return null;
+            }
+        });
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/CredUtils.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/CredUtils.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/CredUtils.java
new file mode 100644
index 0000000..fdcb046
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/CredUtils.java
@@ -0,0 +1,89 @@
+package org.apache.kerby.kerberos.kerb.gss.impl;
+
+import org.ietf.jgss.GSSException;
+import sun.security.jgss.GSSCaller;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.*;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Set;
+
+/**
+ * Utility functions to deal with credentials in Context
+ */
+public class CredUtils {
+
+    public static <T> Set<T> getContextPrivateCredentials(Class<T> credentialType, AccessControlContext acc) {
+        Subject subject = Subject.getSubject(acc);
+        Set<T> creds = subject.getPrivateCredentials(credentialType);
+        return creds;
+    }
+
+    public static <T> Set<T> getContextCredentials(final Class<T> credentialType) throws GSSException {
+        final AccessControlContext acc = AccessController.getContext();
+        try {
+            return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Set<T>>() {
+                        public Set<T> run() throws Exception {
+                            return CredUtils.getContextPrivateCredentials(credentialType, acc);
+                        }
+                    });
+        } catch (PrivilegedActionException e) {
+            throw new GSSException(GSSException.NO_CRED, -1, "Get credential from context failed");
+        }
+    }
+
+    public static KerberosTicket getKerberosTicketFromContext(GSSCaller caller,
+                                                              final String clientName,
+                                                              final String serverName) throws GSSException {
+        Set<KerberosTicket> tickets = getContextCredentials(KerberosTicket.class);
+        for (KerberosTicket ticket : tickets) {
+            if (ticket.isCurrent() && (serverName == null || ticket.getServer().getName().equals(serverName))
+                    && (clientName == null || ticket.getClient().getName().equals(clientName))) {
+                return ticket;
+            }
+        }
+        return null;
+    }
+
+    public static KeyTab getKeyTabFromContext(KerberosPrincipal principal) throws GSSException {
+        Set<KeyTab> tabs = getContextCredentials(KeyTab.class);
+        for (KeyTab tab : tabs) {
+            KerberosKey[] keys = tab.getKeys(principal);
+            if (keys != null && keys.length > 0) {
+                return tab;
+            }
+        }
+        return null;
+    }
+
+    public static void addCredentialToSubject(final KerberosTicket ticket) throws GSSException {
+        final AccessControlContext acc = AccessController.getContext();
+
+        final Subject subject = AccessController.doPrivileged(
+                new java.security.PrivilegedAction<Subject>() {
+                    public Subject run() {
+                        return Subject.getSubject(acc);
+                    }
+                });
+
+        AccessController.doPrivileged(
+                new java.security.PrivilegedAction<Void>() {
+                    public Void run() {
+                        subject.getPrivateCredentials().add(ticket);
+                        return null;
+                    }
+                });
+    }
+
+    public static void checkPrincipalPermission(String principalName, String action) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            ServicePermission sp = new ServicePermission(principalName, action);
+            sm.checkPermission(sp);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssAcceptCred.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssAcceptCred.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssAcceptCred.java
new file mode 100644
index 0000000..9ba718f
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssAcceptCred.java
@@ -0,0 +1,72 @@
+/**
+ *  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.gss.impl;
+
+
+import org.ietf.jgss.GSSException;
+import sun.security.jgss.GSSCaller;
+
+import javax.security.auth.kerberos.KerberosKey;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KeyTab;
+
+public final class GssAcceptCred extends GssCredElement {
+
+    private final KeyTab keyTab;
+
+    public static GssAcceptCred getInstance(final GSSCaller caller,
+                                            GssNameElement name, int lifeTime) throws GSSException {
+
+        KerberosPrincipal princ = new KerberosPrincipal(name.getPrincipalName().getName(),
+                name.getPrincipalName().getNameType().getValue());
+        KeyTab keyTab = CredUtils.getKeyTabFromContext(princ);
+
+        if (keyTab == null) {
+            throw new GSSException(GSSException.NO_CRED, -1,
+                    "Failed to find any Kerberos credential for " + name.getPrincipalName().getName());
+        }
+
+        return new GssAcceptCred(caller, name, keyTab, lifeTime);
+    }
+
+    private GssAcceptCred(GSSCaller caller, GssNameElement name, KeyTab keyTab, int lifeTime) {
+        super(caller, name);
+        this.keyTab = keyTab;
+        this.accLifeTime = lifeTime;
+    }
+
+    public boolean isInitiatorCredential() throws GSSException {
+        return false;
+    }
+
+    public boolean isAcceptorCredential() throws GSSException {
+        return true;
+    }
+
+    public KeyTab getKeyTab() {
+        return this.keyTab;
+    }
+
+    public KerberosKey[] getKeys() {
+        KerberosPrincipal princ = new KerberosPrincipal(name.getPrincipalName().getName(),
+                name.getPrincipalName().getNameType().getValue());
+        return keyTab.getKeys(princ);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/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
new file mode 100644
index 0000000..3efb08b
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssContext.java
@@ -0,0 +1,745 @@
+/**
+ *  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.gss.impl;
+
+import com.sun.security.jgss.InquireType;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.gss.GssMechFactory;
+import org.apache.kerby.kerberos.kerb.gss.KerbyGssProvider;
+import org.apache.kerby.kerberos.kerb.request.ApRequest;
+import org.apache.kerby.kerberos.kerb.response.ApResponse;
+import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationData;
+import org.apache.kerby.kerberos.kerb.type.ap.ApRep;
+import org.apache.kerby.kerberos.kerb.type.ap.ApReq;
+import org.apache.kerby.kerberos.kerb.type.ap.Authenticator;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.apache.kerby.kerberos.kerb.type.kdc.EncKdcRepPart;
+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.TicketFlags;
+import org.ietf.jgss.ChannelBinding;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.MessageProp;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSCaller;
+import sun.security.jgss.spi.GSSContextSpi;
+import sun.security.jgss.spi.GSSCredentialSpi;
+import sun.security.jgss.spi.GSSNameSpi;
+
+import javax.security.auth.kerberos.KerberosTicket;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.security.Provider;
+
+@SuppressWarnings("PMD")
+public class GssContext implements GSSContextSpi {
+
+    private static final int STATE_NONE = 0;
+    private static final int STATE_ESTABLISHING = 1;
+    private static final int STATE_ESTABLISHED = 2;
+    private static final int STATE_DESTROYED = 3;
+
+    private static final byte[] MSG_AP_REQ = {(byte) 0x1, (byte) 0};
+    private static final byte[] MSG_AP_REP = {(byte) 0x2, (byte) 0};
+
+    private int ctxState = STATE_NONE;
+
+    private final GSSCaller caller;
+    private GssCredElement myCred;
+    private boolean initiator;
+    private GssNameElement myName;
+    private GssNameElement peerName;
+    private int lifeTime;
+    private ChannelBinding channelBinding;
+
+    private boolean mutualAuth  = true;
+    private boolean replayDet  = true;
+    private boolean sequenceDet  = true;
+    private boolean credDeleg  = false;
+    private boolean confState  = true;
+    private boolean integState  = true;
+    private boolean delegPolicy = false;
+
+    public static final int INVALID_KEY = 0;
+    public static final int SESSION_KEY = 1;
+    public static final int INITIATOR_SUBKEY = 2;
+    public static final int ACCEPTOR_SUBKEY = 4;
+    private int keyComesFrom = INVALID_KEY;
+
+    private EncryptionKey sessionKey;   // used between client and app server
+    private TicketFlags ticketFlags;
+    private ApReq outApReq;
+
+    private GssEncryptor gssEncryptor;
+
+    // Called on initiator's side.
+    public GssContext(GSSCaller caller, GssNameElement peerName, GssCredElement myCred,
+                      int lifeTime)
+            throws GSSException {
+        if (peerName == null) {
+            throw new IllegalArgumentException("Cannot have null peer name");
+        }
+
+        this.caller = caller;
+        this.peerName = peerName;
+        this.myCred = myCred;
+        this.lifeTime = lifeTime;
+        this.initiator = true;
+
+        mySequenceNumberLock = new Object();
+        peerSequenceNumberLock = new Object();
+    }
+
+    public GssContext(GSSCaller caller, GssAcceptCred myCred)
+            throws GSSException {
+        this.caller = caller;
+        this.myCred = myCred;
+        this.initiator = false;
+
+        mySequenceNumberLock = new Object();
+        peerSequenceNumberLock = new Object();
+    }
+
+    public GssContext(GSSCaller caller, byte[] interProcessToken)
+            throws GSSException {
+        throw new GSSException(GSSException.UNAVAILABLE, -1, "Unsupported feature");
+    }
+
+    public Provider getProvider() {
+        return new KerbyGssProvider();
+    }
+
+    public void requestLifetime(int lifeTime) throws GSSException {
+        if (ctxState == STATE_NONE && isInitiator()) {
+            this.lifeTime = lifeTime;
+        }
+    }
+
+    public void requestMutualAuth(boolean state) throws GSSException {
+        if (ctxState == STATE_NONE && isInitiator()) {
+            mutualAuth  = state;
+        }
+    }
+
+    public void requestReplayDet(boolean state) throws GSSException {
+        if (ctxState == STATE_NONE && isInitiator()) {
+            replayDet = state;
+        }
+    }
+
+    public void requestSequenceDet(boolean state) throws GSSException {
+        if (ctxState == STATE_NONE && isInitiator()) {
+            replayDet = state;
+        }
+    }
+
+    public void requestCredDeleg(boolean state) throws GSSException {
+        if (ctxState == STATE_NONE && isInitiator() && myCred == null) {
+            credDeleg  = state;
+        }
+    }
+
+    public void requestAnonymity(boolean state) throws GSSException {
+        // anonymous context not supported
+    }
+
+    public void requestConf(boolean state) throws GSSException {
+        if (ctxState == STATE_NONE && isInitiator()) {
+            confState = state;
+        }
+    }
+
+    public void requestInteg(boolean state) throws GSSException {
+        if (ctxState == STATE_NONE && isInitiator()) {
+            integState = state;
+        }
+    }
+
+    public void requestDelegPolicy(boolean state) throws GSSException {
+        if (ctxState == STATE_NONE && isInitiator()) {
+            delegPolicy = state;
+        }
+    }
+
+    public void setChannelBinding(ChannelBinding cb) throws GSSException {
+        this.channelBinding = cb;
+    }
+
+    public boolean getCredDelegState() {
+        return credDeleg;
+    }
+
+    public boolean getMutualAuthState() {
+        return mutualAuth;
+    }
+
+    public boolean getReplayDetState() {
+        return replayDet || sequenceDet;
+    }
+
+    public boolean getSequenceDetState() {
+        return sequenceDet;
+    }
+
+    public boolean getAnonymityState() {
+        return false;
+    }
+
+    public boolean getDelegPolicyState() {
+        return delegPolicy;
+    }
+
+    public boolean isTransferable() throws GSSException {
+        return false;
+    }
+
+    public boolean isProtReady() {
+        return ctxState == STATE_ESTABLISHED;
+    }
+
+    public boolean isInitiator() {
+        return initiator;
+    }
+
+    public boolean getConfState() {
+        return confState;
+    }
+
+    public boolean getIntegState() {
+        return integState;
+    }
+
+    public int getLifetime() {
+        return GSSContext.INDEFINITE_LIFETIME;
+    }
+
+    public boolean isEstablished() {
+        return ctxState == STATE_ESTABLISHED;
+    }
+
+    public GSSNameSpi getSrcName() throws GSSException {
+        return isInitiator() ? myName : peerName;
+    }
+
+    public GSSNameSpi getTargName() throws GSSException {
+        return !isInitiator() ? myName : peerName;
+    }
+
+    public Oid getMech() throws GSSException {
+        return GssMechFactory.getOid();
+    }
+
+    public GSSCredentialSpi getDelegCred() throws GSSException {
+        throw new GSSException(GSSException.FAILURE, -1, "API not implemented");  // TODO:
+    }
+
+    public byte[] initSecContext(InputStream is, int mechTokenSize)
+            throws GSSException {
+        if (!isInitiator()) {
+            throw new GSSException(GSSException.FAILURE, -1, "initSecContext called on acceptor");
+        }
+
+        byte[] ret = null;
+
+        if (ctxState == STATE_NONE) {
+
+            if (!myCred.isInitiatorCredential()) {
+                throw new GSSException(GSSException.NO_CRED, -1, "No TGT available");
+            }
+
+            // check if service ticket already exists
+            // if not, prepare to get it through TGS_REQ
+            SgtTicket sgtTicket = null;
+            String serviceName = peerName.getPrincipalName().getName();
+            myName = (GssNameElement) myCred.getName();
+            PrincipalName clientPrincipal = myName.getPrincipalName();
+
+            sgtTicket = GssUtil.getSgtCredentialFromContext(caller, clientPrincipal.getName(), serviceName);
+
+            if (sgtTicket == null) {
+                sgtTicket = GssUtil.applySgtCredential(((GssInitCred) myCred).ticket, serviceName);
+
+                // add this service credential to context
+                final KerberosTicket ticket =
+                        GssUtil.convertKrbTicketToKerberosTicket(sgtTicket, myName.getPrincipalName().getName());
+                CredUtils.addCredentialToSubject(ticket);
+            }
+
+            ApRequest apRequest = new ApRequest(clientPrincipal, sgtTicket);
+            try {
+                outApReq = apRequest.getApReq();
+            } catch (KrbException e) {
+                throw new GSSException(GSSException.FAILURE, -1, "Generate ApReq failed: " + e.getMessage());
+            }
+            setupInitiatorContext(sgtTicket, apRequest);
+            try {
+                ByteBuffer outBuffer = ByteBuffer.allocate(outApReq.encodingLength() + 2);
+                outBuffer.put(MSG_AP_REQ);
+                outApReq.encode(outBuffer);
+                outBuffer.flip();
+                ret = outBuffer.array();
+            } catch (IOException e) {
+                throw new GSSException(GSSException.FAILURE, -1, "Generate ApReq bytes failed: " + e.getMessage());
+            }
+
+            ctxState = STATE_ESTABLISHING;
+            if (!getMutualAuthState()) {
+                gssEncryptor = new GssEncryptor(getSessionKey());
+                ctxState = STATE_ESTABLISHED;
+            }
+
+        } else if (ctxState == STATE_ESTABLISHING) {
+            verifyServerToken(is, mechTokenSize);
+            gssEncryptor = new GssEncryptor(getSessionKey());
+            outApReq = null;
+            ctxState = STATE_ESTABLISHED;
+        }
+        return ret;
+    }
+
+    private void setupInitiatorContext(SgtTicket sgt, ApRequest apRequest) throws GSSException {
+        EncKdcRepPart encKdcRepPart = sgt.getEncKdcRepPart();
+        TicketFlags ticketFlags = encKdcRepPart.getFlags();
+        setTicketFlags(ticketFlags);
+
+        setAuthTime(encKdcRepPart.getAuthTime().toString());
+
+        Authenticator auth;
+        try {
+            auth = apRequest.getApReq().getAuthenticator();
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "ApReq failed in Initiator");
+        }
+        setMySequenceNumber(auth.getSeqNumber());
+
+        EncryptionKey subKey = auth.getSubKey();
+        if (subKey != null) {
+            setSessionKey(subKey, GssContext.INITIATOR_SUBKEY);
+        } else {
+            setSessionKey(sgt.getSessionKey(), GssContext.SESSION_KEY);
+        }
+
+        if (!getMutualAuthState()) {
+            setPeerSequenceNumber(0);
+        }
+    }
+
+    /**
+     * Verify the AP_REP from server and set context accordingly
+     * @param is
+     * @param mechTokenSize
+     * @return
+     * @throws GSSException
+     * @throws IOException
+     */
+    private void verifyServerToken(InputStream is, int mechTokenSize)
+            throws GSSException {
+        byte[] token;
+        ApRep apRep;
+        try {
+            if (!(is.read() == MSG_AP_REP[0] && is.read() == MSG_AP_REP[1])) {
+                throw new GSSException(GSSException.FAILURE, -1, "Invalid ApRep message ID");
+            }
+            token = new byte[mechTokenSize - MSG_AP_REP.length];
+            is.read(token);
+            apRep = new ApRep();
+            apRep.decode(token);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Invalid ApRep " + e.getMessage());
+        }
+
+        try {
+            ApResponse.validate(getSessionKey(), apRep, outApReq);
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.UNAUTHORIZED, -1, "ApRep verification failed");
+        }
+
+        EncryptionKey key = apRep.getEncRepPart().getSubkey();
+        if (key != null) {
+            setSessionKey(key, ACCEPTOR_SUBKEY);
+        }
+
+        int seqNum = apRep.getEncRepPart().getSeqNumber();
+        setPeerSequenceNumber(seqNum == -1 ? 0 : seqNum);
+    }
+
+    public byte[] acceptSecContext(InputStream is, int mechTokenSize)
+            throws GSSException {
+        byte[] ret = null;
+
+        if (isInitiator()) {
+            throw new GSSException(GSSException.FAILURE, -1, "acceptSecContext called on initiator");
+        }
+
+        if (ctxState == STATE_NONE) {
+            ctxState = STATE_ESTABLISHING;
+            if (!myCred.isAcceptorCredential()) {
+                throw new GSSException(GSSException.FAILURE, -1, "No acceptor credential available");
+            }
+
+            GssAcceptCred acceptCred = (GssAcceptCred) myCred;
+            CredUtils.checkPrincipalPermission(
+                    ((GssNameElement) acceptCred.getName()).getPrincipalName().getName(), "accept");
+
+            if (getMutualAuthState()) {
+                ret = verifyClientToken(acceptCred, is, mechTokenSize);
+            }
+
+            gssEncryptor = new GssEncryptor(getSessionKey());
+
+            myCred = null;
+            ctxState = STATE_ESTABLISHED;
+        }
+
+        return ret;
+    }
+
+    private byte[] verifyClientToken(GssAcceptCred acceptCred, InputStream is, int mechTokenSize)
+            throws GSSException {
+        byte[] token;
+        ApReq apReq;
+        try {
+            if (!(is.read() == MSG_AP_REQ[0] && is.read() == MSG_AP_REQ[1])) {
+                throw new GSSException(GSSException.FAILURE, -1, "Invalid ApReq message ID");
+            }
+
+            token = new byte[mechTokenSize - MSG_AP_REQ.length];
+            is.read(token);
+            apReq = new ApReq();
+            apReq.decode(token);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.UNAUTHORIZED, -1, "ApReq invalid:" + e.getMessage());
+        }
+
+        int kvno = apReq.getTicket().getEncryptedEncPart().getKvno();
+        int encryptType = apReq.getTicket().getEncryptedEncPart().getEType().getValue();
+
+        // Get server key from credential
+        EncryptionKey serverKey = GssUtil.getEncryptionKey(acceptCred.getKeys(), encryptType, kvno);
+        if (serverKey == null) {
+            throw new GSSException(GSSException.FAILURE, -1, "Server key not found");
+        }
+
+        try {
+            ApRequest.validate(serverKey, apReq,
+                    channelBinding == null ? null : channelBinding.getInitiatorAddress(), 5 * 60 * 1000);
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.UNAUTHORIZED, -1, "ApReq verification failed: " + e.getMessage());
+        }
+
+        ApResponse apResponse = new ApResponse(apReq);
+        ApRep apRep;
+        try {
+            apRep = apResponse.getApRep();
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.UNAUTHORIZED, -1, "Generate ApRep failed");
+        }
+
+        EncTicketPart apReqTicketEncPart = apReq.getTicket().getEncPart();
+
+        EncryptionKey ssKey = apReqTicketEncPart.getKey();
+        Authenticator auth = apReq.getAuthenticator();
+        EncryptionKey subKey = auth.getSubKey();
+
+        if (subKey != null) {
+            setSessionKey(subKey, INITIATOR_SUBKEY);
+        } else {
+            setSessionKey(ssKey, SESSION_KEY);
+        }
+
+        // initial seqNumber
+        int seqNumber = auth.getSeqNumber();
+        setMySequenceNumber(seqNumber);
+        // initial authtime, tktflags, authdata,
+        setAuthTime(apReqTicketEncPart.getAuthTime().toString());
+        setTicketFlags(apReqTicketEncPart.getFlags());
+        setAuthData(apReqTicketEncPart.getAuthorizationData());
+
+        byte[] ret = null;
+        try {
+            ByteBuffer outBuffer = ByteBuffer.allocate(apRep.encodingLength() + 2);
+            outBuffer.put(MSG_AP_REP);
+            apRep.encode(outBuffer);
+            outBuffer.flip();
+            ret = outBuffer.array();
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Generate ApRep bytes failed:" + e.getMessage());
+        }
+        return ret;
+    }
+
+    public int getWrapSizeLimit(int qop, boolean confReq, int maxTokSize)
+            throws GSSException {
+        if (gssEncryptor.isV2()) {
+            return WrapTokenV2.getMsgSizeLimit(qop, confReq, maxTokSize, gssEncryptor);
+        } else {
+            return WrapTokenV1.getMsgSizeLimit(qop, confReq, maxTokSize, gssEncryptor);
+        }
+    }
+
+    public void wrap(InputStream is, OutputStream os, MessageProp msgProp)
+            throws GSSException {
+        if (ctxState != STATE_ESTABLISHED) {
+            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for wrap");
+        }
+
+        int len;
+        byte[] inBuf;
+        try {
+            len = is.available();
+            inBuf = new byte[len];
+            is.read(inBuf);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Error when get user data:" + e.getMessage());
+        }
+        if (gssEncryptor.isV2()) {
+            WrapTokenV2 token = new WrapTokenV2(this, inBuf, 0, len, msgProp);
+            token.wrap(os);
+        } else {
+            WrapTokenV1 token = new WrapTokenV1(this, inBuf, 0, len, msgProp);
+            token.wrap(os);
+        }
+    }
+
+    public byte[] wrap(byte[] inBuf, int offset, int len,
+                       MessageProp msgProp) throws GSSException {
+        if (ctxState != STATE_ESTABLISHED) {
+            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for wrap");
+        }
+        byte[] ret;
+        if (gssEncryptor.isV2()) {
+            WrapTokenV2 token = new WrapTokenV2(this, inBuf, offset, len, msgProp);
+            ret = token.wrap();
+        } else {
+            WrapTokenV1 token = new WrapTokenV1(this, inBuf, offset, len, msgProp);
+            ret = token.wrap();
+        }
+        return ret;
+    }
+
+    public void unwrap(InputStream is, OutputStream os,
+                       MessageProp msgProp) throws GSSException {
+        if (ctxState != STATE_ESTABLISHED) {
+            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for unwrap");
+        }
+
+        if (gssEncryptor.isV2()) {
+            WrapTokenV2 token = new WrapTokenV2(this, msgProp, is);
+            token.unwrap(os);
+        } else {
+            WrapTokenV1 token = new WrapTokenV1(this, msgProp, is);
+            token.unwrap(os);
+        }
+    }
+
+    public byte[] unwrap(byte[] inBuf, int offset, int len,
+                         MessageProp msgProp) throws GSSException {
+        if (ctxState != STATE_ESTABLISHED) {
+            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for unwrap");
+        }
+
+        byte[] ret;
+        if (gssEncryptor.isV2()) {
+            WrapTokenV2 token = new WrapTokenV2(this, msgProp, inBuf, offset, len);
+            ret = token.unwrap();
+        } else {
+            WrapTokenV1 token = new WrapTokenV1(this, msgProp, inBuf, offset, len);
+            ret = token.unwrap();
+        }
+        return ret;
+    }
+
+    public void getMIC(InputStream is, OutputStream os,
+                       MessageProp msgProp) throws GSSException {
+        if (ctxState != STATE_ESTABLISHED) {
+            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for getMIC");
+        }
+
+        try {
+            int len = is.available();
+            byte[] inMsg = new byte[len];
+            is.read(inMsg);
+            if (gssEncryptor.isV2()) {
+                MicTokenV2 token = new MicTokenV2(this, inMsg, 0, len, msgProp);
+                token.getMic(os);
+            } else {
+                MicTokenV1 token = new MicTokenV1(this, inMsg, 0, len, msgProp);
+                token.getMic(os);
+            }
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Error when get user data in getMIC:" + e.getMessage());
+        }
+    }
+
+    public byte[] getMIC(byte[] inMsg, int offset, int len,
+                         MessageProp msgProp) throws GSSException {
+        if (ctxState != STATE_ESTABLISHED) {
+            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for getMIC");
+        }
+
+        byte[] ret;
+        if (gssEncryptor.isV2()) {
+            MicTokenV2 token = new MicTokenV2(this, inMsg, offset, len, msgProp);
+            ret = token.getMic();
+        } else {
+            MicTokenV1 token = new MicTokenV1(this, inMsg, offset, len, msgProp);
+            ret = token.getMic();
+        }
+        return ret;
+    }
+
+    public void verifyMIC(InputStream is, InputStream msgStr,
+                          MessageProp msgProp) throws GSSException {
+        if (ctxState != STATE_ESTABLISHED) {
+            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for verifyMIC");
+        }
+
+        try {
+            int tokLen = is.available();
+            byte[] inTok = new byte[tokLen];
+            int msgLen = msgStr.available();
+            byte[] inMsg = new byte[msgLen];
+
+           verifyMIC(inTok, 0, tokLen, inMsg, 0, msgLen, msgProp);
+        } catch (IOException e) {
+            throw new GSSException(GSSException.FAILURE, -1,
+                    "Error when get user data in verifyMIC:" + e.getMessage());
+        }
+    }
+
+    public void verifyMIC(byte[]inTok, int tokOffset, int tokLen,
+                          byte[] inMsg, int msgOffset, int msgLen,
+                          MessageProp msgProp) throws GSSException {
+        if (ctxState != STATE_ESTABLISHED) {
+            throw new GSSException(GSSException.NO_CONTEXT, -1, "Context invalid for verifyMIC");
+        }
+
+        if (gssEncryptor.isV2()) {
+            MicTokenV2 token = new MicTokenV2(this, msgProp, inTok, tokOffset, tokLen);
+            token.verify(inMsg, msgOffset, msgLen);
+        } else {
+            MicTokenV1 token = new MicTokenV1(this, msgProp, inTok, tokOffset, tokLen);
+            token.verify(inMsg, msgOffset, msgLen);
+        }
+    }
+
+    public byte[] export() throws GSSException {
+        throw new GSSException(GSSException.UNAVAILABLE, -1, "Unsupported export() method");
+    }
+
+    public void dispose() throws GSSException {
+        ctxState = STATE_DESTROYED;
+        setSessionKey(null, 0);
+        peerName = null;
+        myCred = null;
+        myName = null;
+    }
+
+
+    private String authTime;
+    private void setAuthTime(String authTime) {
+        this.authTime = authTime;
+    }
+
+    public Object inquireSecContext(InquireType type) throws GSSException {
+        if (ctxState != STATE_ESTABLISHED) {
+            throw new GSSException(GSSException.NO_CONTEXT, -1, "Invalid context");
+        }
+
+        switch (type) {
+            case KRB5_GET_SESSION_KEY:
+                return getSessionKey();
+            case KRB5_GET_TKT_FLAGS:
+                return GssUtil.ticketFlagsToBooleans(ticketFlags);
+            case KRB5_GET_AUTHZ_DATA:
+                if (isInitiator()) {
+                    throw new GSSException(GSSException.UNAVAILABLE, -1,
+                            "Authorization data not available for initiator");
+                } else {
+                    return GssUtil.kerbyAuthorizationDataToJgssAuthorizationDataEntries(authData);
+                }
+            case KRB5_GET_AUTHTIME:
+                return authTime;
+        }
+        throw new GSSException(GSSException.UNAVAILABLE, -1, "Unsupported inquire type");
+    }
+
+
+    // functions not belong to SPI
+    private void setSessionKey(EncryptionKey encryptionKey, int keyComesFrom) {
+        this.sessionKey = encryptionKey;
+        this.keyComesFrom = keyComesFrom;
+    }
+
+    public int getKeyComesFrom() {
+        return keyComesFrom;
+    }
+
+    private EncryptionKey getSessionKey() {
+        return sessionKey;
+    }
+
+    private void setTicketFlags(TicketFlags ticketFlags) {
+        this.ticketFlags = ticketFlags;
+    }
+
+    private AuthorizationData authData;
+    private void setAuthData(AuthorizationData authData) {
+        this.authData = authData;
+    }
+
+
+    private int mySequenceNumber;
+    private int peerSequenceNumber;
+    private Object mySequenceNumberLock;
+    private Object peerSequenceNumberLock;
+
+    public void setMySequenceNumber(int sequenceNumber) {
+        synchronized (mySequenceNumberLock) {
+            mySequenceNumber = sequenceNumber;
+        }
+    }
+
+    public int incMySequenceNumber() {
+        synchronized (mySequenceNumberLock) {
+            return mySequenceNumber++;
+        }
+    }
+
+    public void setPeerSequenceNumber(int sequenceNumber) {
+        synchronized (peerSequenceNumberLock) {
+            peerSequenceNumber = sequenceNumber;
+        }
+    }
+
+    public int incPeerSequenceNumber() {
+        synchronized (peerSequenceNumberLock) {
+            return peerSequenceNumber++;
+        }
+    }
+
+    public GssEncryptor getGssEncryptor() {
+        return gssEncryptor;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssCredElement.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssCredElement.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssCredElement.java
new file mode 100644
index 0000000..657f222
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssCredElement.java
@@ -0,0 +1,81 @@
+/**
+ *  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.gss.impl;
+
+import org.apache.kerby.kerberos.kerb.gss.KerbyGssProvider;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSCaller;
+import sun.security.jgss.spi.GSSCredentialSpi;
+import sun.security.jgss.spi.GSSNameSpi;
+
+import java.security.Provider;
+
+public abstract class GssCredElement implements GSSCredentialSpi {
+
+    static final Oid KRB5_OID = createOid("1.2.840.113554.1.2.2");
+
+    protected GSSCaller caller;
+    protected GssNameElement name;
+    protected int initLifeTime;
+    protected int accLifeTime;
+
+    GssCredElement(GSSCaller caller, GssNameElement name) {
+        this.caller = caller;
+        this.name = name;
+    }
+
+    public Provider getProvider() {
+        return new KerbyGssProvider();
+    }
+
+    public void dispose() throws GSSException {
+    }
+
+    public GSSNameSpi getName() throws GSSException {
+        return name;
+    }
+
+    public int getInitLifetime() throws GSSException {
+        return initLifeTime;
+    }
+
+    public int getAcceptLifetime() throws GSSException {
+        return accLifeTime;
+    }
+
+    public Oid getMechanism() {
+        return KRB5_OID;
+    }
+
+    public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
+        throw new GSSException(GSSException.FAILURE, -1, "Unsupported feature");  // TODO:
+    }
+
+    private static Oid createOid(String oidStr) {
+        Oid retVal;
+        try {
+            retVal = new Oid(oidStr);
+        } catch (GSSException e) {
+            retVal = null; // get rid of blank catch block warning
+        }
+        return retVal;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssEncryptor.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssEncryptor.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssEncryptor.java
new file mode 100644
index 0000000..4eb96e3
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssEncryptor.java
@@ -0,0 +1,388 @@
+/**
+ *  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.gss.impl;
+
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.crypto.CheckSumHandler;
+import org.apache.kerby.kerberos.kerb.crypto.CheckSumTypeHandler;
+import org.apache.kerby.kerberos.kerb.crypto.EncTypeHandler;
+import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
+import org.apache.kerby.kerberos.kerb.crypto.cksum.provider.Md5Provider;
+import org.apache.kerby.kerberos.kerb.crypto.enc.provider.DesProvider;
+import org.apache.kerby.kerberos.kerb.crypto.enc.provider.Rc4Provider;
+import org.apache.kerby.kerberos.kerb.type.base.CheckSumType;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
+import org.ietf.jgss.GSSException;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * This class implements encryption related function used in GSS tokens
+ */
+public class GssEncryptor {
+
+    private final EncryptionKey encKey;
+    private final EncryptionType encKeyType; // The following two variables used for convenience
+    private final byte[] encKeyBytes;
+
+    private CheckSumType checkSumTypeDef;
+    private int checkSumSize;
+
+    private boolean isV2 = false;
+    private int sgnAlg = 0xFFFF;
+    private int sealAlg = 0xFFFF;
+    private boolean isArcFourHmac = false;
+
+    private static final byte[] IV_ZEROR_8B = new byte[8];
+
+    public GssEncryptor(EncryptionKey key) throws GSSException {
+        encKey = key;
+        encKeyBytes = encKey.getKeyData();
+        encKeyType = key.getKeyType();
+
+        if (encKeyType == EncryptionType.AES128_CTS_HMAC_SHA1_96) {
+            checkSumSize = 12;
+            checkSumTypeDef = CheckSumType.HMAC_SHA1_96_AES128;
+            isV2 = true;
+        } else if (encKeyType == EncryptionType.AES256_CTS_HMAC_SHA1_96) {
+            checkSumSize = 12;
+            checkSumTypeDef = CheckSumType.HMAC_SHA1_96_AES256;
+            isV2 = true;
+        } else if (encKeyType == EncryptionType.DES_CBC_CRC || encKeyType == EncryptionType.DES_CBC_MD5) {
+            sgnAlg = GssTokenV1.SGN_ALG_DES_MAC_MD5;
+            sealAlg = GssTokenV1.SEAL_ALG_DES;
+            checkSumSize = 8;
+        } else if (encKeyType == EncryptionType.DES3_CBC_SHA1) {
+            sgnAlg = GssTokenV1.SGN_ALG_HMAC_SHA1_DES3_KD;
+            sealAlg = GssTokenV1.SEAL_ALG_DES3_KD;
+            checkSumSize = 20;
+        } else if (encKeyType == EncryptionType.ARCFOUR_HMAC) {
+            sgnAlg = GssTokenV1.SGN_ALG_RC4_HMAC;
+            sealAlg = GssTokenV1.SEAL_ALG_RC4_HMAC;
+            checkSumSize = 16;
+            isArcFourHmac = true;
+        } else {
+            throw new GSSException(GSSException.FAILURE, -1,
+                    "Invalid encryption type: " + encKeyType.getDisplayName());
+        }
+    }
+
+    /**
+     * Return true if it is encryption type defined in RFC 4121
+     * @return
+     */
+    public boolean isV2() {
+        return isV2;
+    }
+
+    public int getSgnAlg() {
+        return sgnAlg;
+    }
+
+    public int getSealAlg() {
+        return sealAlg;
+    }
+
+    public boolean isArcFourHmac() {
+        return isArcFourHmac;
+    }
+
+    public byte[] encryptData(byte[] tokenHeader, byte[] data,
+                              int offset, int len, int keyUsage) throws GSSException {
+        byte[] ret;
+        byte[] toProcess = new byte[tokenHeader.length + len];
+        System.arraycopy(data, offset, toProcess, 0, len);
+        System.arraycopy(tokenHeader, 0, toProcess, len, tokenHeader.length);
+
+        ret = encryptData(toProcess, keyUsage);
+        return ret;
+    }
+
+    public byte[] encryptData(byte[] toProcess, int keyUsage) throws GSSException {
+        byte[] ret;
+        try {
+            EncTypeHandler encHandler = EncryptionHandler.getEncHandler(encKey.getKeyType());
+            ret = encHandler.encrypt(toProcess, encKey.getKeyData(), keyUsage);
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
+        }
+        return ret;
+    }
+
+    public byte[] decryptData(byte[] dataEncrypted, int keyUsage) throws GSSException {
+        byte[] ret;
+        try {
+            EncTypeHandler encHandler = EncryptionHandler.getEncHandler(encKey.getKeyType());
+            ret = encHandler.decrypt(dataEncrypted, encKey.getKeyData(), keyUsage);
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.FAILURE, -1, e.getMessage());
+        }
+        return ret;
+    }
+
+    public byte[] calculateCheckSum(byte[] header, byte[] data, int offset, int len, int keyUsage)
+            throws GSSException {
+        int totalLen = len + (header == null ? 0 : header.length);
+        byte[] buffer = new byte[totalLen];
+        System.arraycopy(data, offset, buffer, 0, len);
+        if (header != null) {
+            System.arraycopy(header, 0, buffer, len, header.length);
+        }
+
+        try {
+            return CheckSumHandler.getCheckSumHandler(checkSumTypeDef)
+                    .checksumWithKey(buffer, encKey.getKeyData(), keyUsage);
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.FAILURE, -1,
+                    "Exception in checksum calculation:" + e.getMessage());
+        }
+    }
+
+    /**
+     * Get the size of the corresponding checksum algorithm
+     * @return
+     * @throws GSSException
+     */
+    public int getCheckSumSize() throws GSSException {
+        return checkSumSize;
+    }
+
+
+    private void addPadding(int paddingLen, byte[] outBuf, int offset) {
+        for (int i = 0; i < paddingLen; i++) {
+            outBuf[offset + i] = (byte) paddingLen;
+        }
+    }
+
+    private byte[] getFirstBytes(byte[] src, int len) {
+        if (len < src.length) {
+            byte[] ret = new byte[len];
+            System.arraycopy(src, 0, ret, 0, len);
+            return ret;
+        }
+        return src;
+    }
+
+    private byte[] getKeyBytesWithLength(int len) {
+        return getFirstBytes(encKeyBytes, len);
+    }
+
+    public byte[] calculateCheckSum(byte[] confounder, byte[] header,
+                                    byte[] data, int offset, int len, int paddingLen, boolean isMic)
+            throws GSSException {
+        byte[] ret;
+        int keyUsage = GssTokenV1.KG_USAGE_SIGN;
+        CheckSumTypeHandler handler;
+
+        int keySize;
+        byte[] key;
+        byte[] toProc;
+        int toOffset;
+        int toLen = (confounder == null ? 0 : confounder.length)
+                + (header == null ? 0 : header.length) + len + paddingLen;
+        if (toLen == len) {
+            toProc = data;
+            toOffset = offset;
+        } else {
+            toOffset = 0;
+            int idx = 0;
+            toProc = new byte[toLen];
+
+            if (header != null) {
+                System.arraycopy(header, 0, toProc, idx, header.length);
+                idx += header.length;
+            }
+
+            if (confounder != null) {
+                System.arraycopy(confounder, 0, toProc, idx, confounder.length);
+                idx += confounder.length;
+            }
+
+            System.arraycopy(data, offset, toProc, idx, len);
+            addPadding(paddingLen, toProc, len + idx);
+        }
+
+        CheckSumType chksumType;
+        try {
+            switch (sgnAlg) {
+                case GssTokenV1.SGN_ALG_DES_MAC_MD5:
+                    Md5Provider md5Provider = new Md5Provider();
+                    md5Provider.hash(toProc);
+                    toProc = md5Provider.output();
+
+                case GssTokenV1.SGN_ALG_DES_MAC:
+                    DesProvider desProvider = new DesProvider();
+                    return desProvider.cbcMac(encKeyBytes, IV_ZEROR_8B, toProc);
+
+                case GssTokenV1.SGN_ALG_HMAC_SHA1_DES3_KD:
+                    chksumType = CheckSumType.HMAC_SHA1_DES3_KD;
+                    break;
+                case GssTokenV1.SGN_ALG_RC4_HMAC:
+                    chksumType = CheckSumType.MD5_HMAC_ARCFOUR;
+                    if (isMic) {
+                        keyUsage = GssTokenV1.KG_USAGE_MS_SIGN;
+                    }
+                    break;
+                case GssTokenV1.SGN_ALG_MD25:
+                    throw new GSSException(GSSException.FAILURE, -1, "CheckSum not implemented for SGN_ALG_MD25");
+                default:
+                    throw new GSSException(GSSException.FAILURE, -1, "CheckSum not implemented for sgnAlg=" + sgnAlg);
+            }
+            handler = CheckSumHandler.getCheckSumHandler(chksumType);
+            keySize = handler.keySize();
+            key = getKeyBytesWithLength(keySize);
+            ret = handler.checksumWithKey(toProc, toOffset, toLen, key, keyUsage);
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.FAILURE, -1,
+                    "Exception in checksum calculation sgnAlg = " + sgnAlg + " : " + e.getMessage());
+        }
+        return ret;
+    }
+
+    public byte[] encryptSequenceNumber(byte[] seqBytes, byte[] ivSrc, boolean encrypt)
+            throws GSSException {
+        EncTypeHandler handler;
+        try {
+            switch (sgnAlg) {
+                case GssTokenV1.SGN_ALG_DES_MAC_MD5:
+                case GssTokenV1.SGN_ALG_DES_MAC:
+                    DesProvider desProvider = new DesProvider();
+                    byte[] data = seqBytes.clone();
+                    if (encrypt) {
+                        desProvider.encrypt(encKeyBytes, ivSrc, data);
+                    } else {
+                        desProvider.decrypt(encKeyBytes, ivSrc, data);
+                    }
+                    return data;
+                case GssTokenV1.SGN_ALG_HMAC_SHA1_DES3_KD:
+                    handler = EncryptionHandler.getEncHandler(EncryptionType.DES3_CBC_SHA1_KD);
+                    break;
+                case GssTokenV1.SGN_ALG_RC4_HMAC:
+                    return encryptArcFourHmac(seqBytes, getKeyBytesWithLength(16), getFirstBytes(ivSrc, 8), encrypt);
+                case GssTokenV1.SGN_ALG_MD25:
+                    throw new GSSException(GSSException.FAILURE, -1, "EncSeq not implemented for SGN_ALG_MD25");
+                default:
+                    throw new GSSException(GSSException.FAILURE, -1, "EncSeq not implemented for sgnAlg=" + sgnAlg);
+            }
+            int keySize = handler.keySize();
+            byte[] key = getKeyBytesWithLength(keySize);
+            int ivLen = handler.encProvider().blockSize();
+            byte[] iv = getFirstBytes(ivSrc, ivLen);
+            if (encrypt) {
+                return handler.encryptRaw(seqBytes, key, iv, GssTokenV1.KG_USAGE_SEQ);
+            } else {
+                return handler.decryptRaw(seqBytes, key, iv, GssTokenV1.KG_USAGE_SEQ);
+            }
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.FAILURE, -1,
+                    "Exception in encrypt seq number sgnAlg = " + sgnAlg + " : " + e.getMessage());
+        }
+    }
+
+    private byte[] getHmacMd5(byte[] key, byte[] salt) throws GSSException {
+        try {
+            SecretKey secretKey = new SecretKeySpec(key, "HmacMD5");
+            Mac mac = Mac.getInstance("HmacMD5");
+            mac.init(secretKey);
+            return mac.doFinal(salt);
+        } catch (Exception e) {
+            throw new GSSException(GSSException.FAILURE, -1, "Get HmacMD5 failed: " + e.getMessage());
+        }
+    }
+
+    private byte[] encryptArcFourHmac(byte[] data, byte[] key, byte[] iv, boolean encrypt)
+            throws GSSException {
+        byte[] sk1 = getHmacMd5(key, new byte[4]);
+        byte[] sk2 = getHmacMd5(sk1, iv);
+        Rc4Provider provider = new Rc4Provider();
+        try {
+            byte[] ret = data.clone();
+            if (encrypt) {
+                provider.encrypt(sk2, ret);
+            } else {
+                provider.decrypt(sk2, ret);
+            }
+            return ret;
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.FAILURE, -1,
+                    "En/Decrypt sequence failed for ArcFourHmac: " + e.getMessage());
+        }
+    }
+
+    private byte[] encryptDataArcFourHmac(byte[] data, byte[] key, byte[] seqNum, boolean encrypt) throws GSSException {
+        byte[] dataKey = new byte[key.length];
+        for (int i = 0; i <= 15; i++) {
+            dataKey[i] = (byte) (key[i] ^ 0xF0);
+        }
+        return encryptArcFourHmac(data, dataKey, seqNum, encrypt);
+    }
+
+    public byte[] encryptTokenV1(byte[] confounder, byte[] data, int offset, int len,
+                            int paddingLen, byte[] seqNumber, boolean encrypt) throws GSSException {
+        byte[] toProc;
+        if (encrypt) {
+            int toLen = (confounder == null ? 0 : confounder.length) + len + paddingLen;
+            int index = 0;
+            toProc = new byte[toLen];
+            if (confounder != null) {
+                System.arraycopy(confounder, 0, toProc, 0, confounder.length);
+                index += confounder.length;
+            }
+            System.arraycopy(data, offset, toProc, index, len);
+            addPadding(paddingLen, toProc, index + len);
+        } else {
+            toProc = data;
+            if (data.length != len) {
+                toProc = new byte[len];
+                System.arraycopy(data, offset, toProc, 0, len);
+            }
+        }
+        EncTypeHandler handler;
+        try {
+            switch (sealAlg) {
+                case GssTokenV1.SEAL_ALG_DES:
+                    handler = EncryptionHandler.getEncHandler(EncryptionType.DES_CBC_MD5);
+                    break;
+                case GssTokenV1.SEAL_ALG_DES3_KD:
+                    handler = EncryptionHandler.getEncHandler(EncryptionType.DES3_CBC_SHA1_KD);
+                    break;
+                case GssTokenV1.SEAL_ALG_RC4_HMAC:
+                    return encryptDataArcFourHmac(toProc, getKeyBytesWithLength(16), seqNumber, encrypt);
+                default:
+                    throw new GSSException(GSSException.FAILURE, -1, "Unknown encryption type sealAlg = " + sealAlg);
+            }
+
+            int keySize = handler.keySize();
+            byte[] key = getKeyBytesWithLength(keySize);
+            if (encrypt) {
+                return handler.encryptRaw(toProc, key, GssTokenV1.KG_USAGE_SEAL);
+            } else {
+                return handler.decryptRaw(toProc, key, GssTokenV1.KG_USAGE_SEAL);
+            }
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.FAILURE, -1,
+                    "Exception in encrypt data sealAlg = " + sealAlg + " : " + e.getMessage());
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/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
new file mode 100644
index 0000000..0b2516d
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssInitCred.java
@@ -0,0 +1,53 @@
+/**
+ *  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.gss.impl;
+
+import org.ietf.jgss.GSSException;
+import sun.security.jgss.GSSCaller;
+
+import javax.security.auth.kerberos.KerberosTicket;
+
+public final class GssInitCred extends GssCredElement {
+
+    public KerberosTicket ticket;
+
+    private GssInitCred(GSSCaller caller, GssNameElement name, KerberosTicket ticket, int lifeTime) {
+        super(caller, name);
+        this.ticket = ticket;
+        this.initLifeTime = lifeTime;
+    }
+
+    public static GssInitCred getInstance(GSSCaller caller, GssNameElement name, int lifeTime) throws GSSException {
+        KerberosTicket ticket = CredUtils.getKerberosTicketFromContext(caller, name.getPrincipalName().getName(), null);
+        return new GssInitCred(caller, name, ticket, lifeTime);
+    }
+
+    public boolean isInitiatorCredential() throws GSSException {
+        return true;
+    }
+
+    public boolean isAcceptorCredential() throws GSSException {
+        return false;
+    }
+
+    public KerberosTicket getKerberosTicket() {
+        return ticket;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssNameElement.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssNameElement.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssNameElement.java
new file mode 100644
index 0000000..bd5c8a4
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssNameElement.java
@@ -0,0 +1,135 @@
+/**
+ *  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.gss.impl;
+
+import org.apache.kerby.kerberos.kerb.gss.GssMechFactory;
+import org.apache.kerby.kerberos.kerb.gss.KerbyGssProvider;
+import org.apache.kerby.kerberos.kerb.type.base.NameType;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.spi.GSSNameSpi;
+import java.io.UnsupportedEncodingException;
+import java.security.Provider;
+
+public class GssNameElement implements GSSNameSpi {
+
+    private PrincipalName principalName;
+    private Oid nameType = null;
+
+    GssNameElement(PrincipalName principalName,
+                   Oid nameType) {
+        this.principalName = principalName;
+        this.nameType = nameType;
+    }
+
+    public PrincipalName toKerbyPrincipalName(sun.security.krb5.PrincipalName name) {
+        return new PrincipalName(name.getNameString(), toKerbyNameType(name.getNameType()));
+    }
+
+    private NameType toKerbyNameType(int intNameType) {
+        return NameType.fromValue(intNameType);
+    }
+
+    public static NameType toKerbyNameType(Oid nameType) throws GSSException {
+        NameType kerbyNameType;
+
+        if (nameType == null) {
+            throw new GSSException(GSSException.BAD_NAMETYPE);
+        }
+
+        if (nameType.equals(GSSName.NT_EXPORT_NAME) || nameType.equals(GSSName.NT_USER_NAME)) {
+            kerbyNameType = NameType.NT_PRINCIPAL;
+        } else if (nameType.equals(GSSName.NT_HOSTBASED_SERVICE)) {
+            kerbyNameType = NameType.NT_SRV_HST;
+        } else {
+            throw new GSSException(GSSException.BAD_NAMETYPE, 0, "Unsupported Oid name type");
+        }
+        return kerbyNameType;
+    }
+
+    public static GssNameElement getInstance(String name, Oid oidNameType)
+            throws GSSException {
+        PrincipalName principalName = new PrincipalName(name, toKerbyNameType(oidNameType));
+        return new GssNameElement(principalName, oidNameType);
+    }
+
+    public Provider getProvider() {
+        return new KerbyGssProvider();
+    }
+
+    public boolean equals(GSSNameSpi name) throws GSSException {
+        if (name == null || name.isAnonymousName() || isAnonymousName()) {
+            return false;
+        }
+        return this.toString().equals(name.toString()) && this.getStringNameType().equals(name.getStringNameType());
+    }
+
+    public final PrincipalName getPrincipalName() {
+        return principalName;
+    }
+
+    public boolean equals(Object another) {
+        if (another == null) {
+            return false;
+        }
+
+        try {
+            if (another instanceof GSSNameSpi) {
+                return equals((GSSNameSpi) another);
+            }
+        } catch (GSSException e) {
+            return false;
+        }
+
+        return false;
+    }
+
+    public int hashCode() {
+        return principalName.hashCode();
+    }
+
+    public byte[] export() throws GSSException {
+        byte[] retVal;
+        try {
+            retVal = principalName.getName().getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new GSSException(GSSException.BAD_NAME, -1, e.getMessage());
+        }
+        return retVal;
+    }
+
+    public Oid getMechanism() {
+        return GssMechFactory.getOid();
+    }
+
+    public String toString() {
+        return principalName.toString();
+    }
+
+    public Oid getStringNameType() {
+        return nameType;
+    }
+
+    public boolean isAnonymousName() {
+        return nameType.equals(GSSName.NT_ANONYMOUS);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/8432c1a8/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenBase.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenBase.java b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenBase.java
new file mode 100644
index 0000000..ec66aa5
--- /dev/null
+++ b/kerby-kerb/kerb-gssapi/src/main/java/org/apache/kerby/kerberos/kerb/gss/impl/GssTokenBase.java
@@ -0,0 +1,59 @@
+/**
+ *  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.gss.impl;
+
+
+public abstract class GssTokenBase {
+    public static final int TOKEN_WRAP_V1 = 0x201;
+    public static final int TOKEN_MIC_V1 = 0x101;
+    public static final int TOKEN_WRAP_V2 = 0x504;
+    public static final int TOKEN_MIC_V2 = 0x404;
+
+    public void writeBigEndian(byte[] buf, int offset, int value) {
+        buf[offset] = (byte) (value >>> 24);
+        buf[offset + 1] = (byte) (value >>> 16);
+        buf[offset + 2] = (byte) (value >>> 8);
+        buf[offset + 3] = (byte) (value);
+    }
+
+    public int readBigEndian(byte[] buf, int offset) {
+        int value = 0;
+        value += (buf[offset] & 0xFF) << 24;
+        value += (buf[offset + 1] & 0xFF) << 16;
+        value += (buf[offset + 2] & 0xFF) << 8;
+        value += buf[offset + 3] & 0xFF;
+        return value;
+    }
+
+    /**
+     *
+     * @param buf
+     * @param offset
+     * @param len should not be larger than sizeof(int)
+     * @return
+     */
+    public int readBigEndian(byte[] buf, int offset, int len) {
+        int value = 0;
+        for (int i = 0; i < len; i++) {
+            value += (buf[offset + i] & 0xFF) << 8;
+        }
+        return value;
+    }
+}