src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java
changeset 47216 71c04702a3d5
parent 40255 0222e4232e7c
child 50750 45511dcfed3f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.jgss.krb5;
+
+import org.ietf.jgss.*;
+import sun.security.jgss.GSSCaller;
+import sun.security.jgss.spi.*;
+import sun.security.krb5.*;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import java.net.InetAddress;
+import java.io.IOException;
+import java.util.Date;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+
+/**
+ * Implements the krb5 initiator credential element.
+ *
+ * @author Mayank Upadhyay
+ * @author Ram Marti
+ * @since 1.4
+ */
+
+public class Krb5InitCredential
+    extends KerberosTicket
+    implements Krb5CredElement {
+
+    private static final long serialVersionUID = 7723415700837898232L;
+
+    private Krb5NameElement name;
+    private Credentials krb5Credentials;
+
+    private Krb5InitCredential(Krb5NameElement name,
+                               byte[] asn1Encoding,
+                               KerberosPrincipal client,
+                               KerberosPrincipal server,
+                               byte[] sessionKey,
+                               int keyType,
+                               boolean[] flags,
+                               Date authTime,
+                               Date startTime,
+                               Date endTime,
+                               Date renewTill,
+                               InetAddress[] clientAddresses)
+                               throws GSSException {
+        super(asn1Encoding,
+              client,
+              server,
+              sessionKey,
+              keyType,
+              flags,
+              authTime,
+              startTime,
+              endTime,
+              renewTill,
+              clientAddresses);
+
+        this.name = name;
+
+        try {
+            // Cache this for later use by the sun.security.krb5 package.
+            krb5Credentials = new Credentials(asn1Encoding,
+                                              client.getName(),
+                                              server.getName(),
+                                              sessionKey,
+                                              keyType,
+                                              flags,
+                                              authTime,
+                                              startTime,
+                                              endTime,
+                                              renewTill,
+                                              clientAddresses);
+        } catch (KrbException e) {
+            throw new GSSException(GSSException.NO_CRED, -1,
+                                   e.getMessage());
+        } catch (IOException e) {
+            throw new GSSException(GSSException.NO_CRED, -1,
+                                   e.getMessage());
+        }
+
+    }
+
+    private Krb5InitCredential(Krb5NameElement name,
+                               Credentials delegatedCred,
+                               byte[] asn1Encoding,
+                               KerberosPrincipal client,
+                               KerberosPrincipal server,
+                               byte[] sessionKey,
+                               int keyType,
+                               boolean[] flags,
+                               Date authTime,
+                               Date startTime,
+                               Date endTime,
+                               Date renewTill,
+                               InetAddress[] clientAddresses)
+                               throws GSSException {
+        super(asn1Encoding,
+              client,
+              server,
+              sessionKey,
+              keyType,
+              flags,
+              authTime,
+              startTime,
+              endTime,
+              renewTill,
+              clientAddresses);
+
+        this.name = name;
+        // A delegated cred does not have all fields set. So do not try to
+        // creat new Credentials out of the delegatedCred.
+        this.krb5Credentials = delegatedCred;
+    }
+
+    static Krb5InitCredential getInstance(GSSCaller caller, Krb5NameElement name,
+                                   int initLifetime)
+        throws GSSException {
+
+        KerberosTicket tgt = getTgt(caller, name, initLifetime);
+        if (tgt == null)
+            throw new GSSException(GSSException.NO_CRED, -1,
+                                   "Failed to find any Kerberos tgt");
+
+        if (name == null) {
+            String fullName = tgt.getClient().getName();
+            name = Krb5NameElement.getInstance(fullName,
+                                       Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
+        }
+
+        return new Krb5InitCredential(name,
+                                      tgt.getEncoded(),
+                                      tgt.getClient(),
+                                      tgt.getServer(),
+                                      tgt.getSessionKey().getEncoded(),
+                                      tgt.getSessionKeyType(),
+                                      tgt.getFlags(),
+                                      tgt.getAuthTime(),
+                                      tgt.getStartTime(),
+                                      tgt.getEndTime(),
+                                      tgt.getRenewTill(),
+                                      tgt.getClientAddresses());
+    }
+
+    static Krb5InitCredential getInstance(Krb5NameElement name,
+                                   Credentials delegatedCred)
+        throws GSSException {
+
+        EncryptionKey sessionKey = delegatedCred.getSessionKey();
+
+        /*
+         * all of the following data is optional in a KRB-CRED
+         * messages. This check for each field.
+         */
+
+        PrincipalName cPrinc = delegatedCred.getClient();
+        PrincipalName sPrinc = delegatedCred.getServer();
+
+        KerberosPrincipal client = null;
+        KerberosPrincipal server = null;
+
+        Krb5NameElement credName = null;
+
+        if (cPrinc != null) {
+            String fullName = cPrinc.getName();
+            credName = Krb5NameElement.getInstance(fullName,
+                               Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
+            client =  new KerberosPrincipal(fullName);
+        }
+
+        // XXX Compare name to credName
+
+        if (sPrinc != null) {
+            server =
+                new KerberosPrincipal(sPrinc.getName(),
+                                        KerberosPrincipal.KRB_NT_SRV_INST);
+        }
+
+        return new Krb5InitCredential(credName,
+                                      delegatedCred,
+                                      delegatedCred.getEncoded(),
+                                      client,
+                                      server,
+                                      sessionKey.getBytes(),
+                                      sessionKey.getEType(),
+                                      delegatedCred.getFlags(),
+                                      delegatedCred.getAuthTime(),
+                                      delegatedCred.getStartTime(),
+                                      delegatedCred.getEndTime(),
+                                      delegatedCred.getRenewTill(),
+                                      delegatedCred.getClientAddresses());
+    }
+
+    /**
+     * Returns the principal name for this credential. The name
+     * is in mechanism specific format.
+     *
+     * @return GSSNameSpi representing principal name of this credential
+     * @exception GSSException may be thrown
+     */
+    public final GSSNameSpi getName() throws GSSException {
+        return name;
+    }
+
+    /**
+     * Returns the init lifetime remaining.
+     *
+     * @return the init lifetime remaining in seconds
+     * @exception GSSException may be thrown
+     */
+    public int getInitLifetime() throws GSSException {
+        int retVal = 0;
+        Date d = getEndTime();
+        if (d == null) {
+            return 0;
+        }
+        retVal = (int)(d.getTime() - (new Date().getTime()));
+
+        return retVal/1000;
+    }
+
+    /**
+     * Returns the accept lifetime remaining.
+     *
+     * @return the accept lifetime remaining in seconds
+     * @exception GSSException may be thrown
+     */
+    public int getAcceptLifetime() throws GSSException {
+        return 0;
+    }
+
+    public boolean isInitiatorCredential() throws GSSException {
+        return true;
+    }
+
+    public boolean isAcceptorCredential() throws GSSException {
+        return false;
+    }
+
+    /**
+     * Returns the oid representing the underlying credential
+     * mechanism oid.
+     *
+     * @return the Oid for this credential mechanism
+     * @exception GSSException may be thrown
+     */
+    public final Oid getMechanism() {
+        return Krb5MechFactory.GSS_KRB5_MECH_OID;
+    }
+
+    public final java.security.Provider getProvider() {
+        return Krb5MechFactory.PROVIDER;
+    }
+
+
+    /**
+     * Returns a sun.security.krb5.Credentials instance so that it maybe
+     * used in that package for th Kerberos protocol.
+     */
+    Credentials getKrb5Credentials() {
+        return krb5Credentials;
+    }
+
+    /*
+     * XXX Call to this.refresh() should refresh the locally cached copy
+     * of krb5Credentials also.
+     */
+
+    /**
+     * Called to invalidate this credential element.
+     */
+    public void dispose() throws GSSException {
+        try {
+            destroy();
+        } catch (javax.security.auth.DestroyFailedException e) {
+            GSSException gssException =
+                new GSSException(GSSException.FAILURE, -1,
+                 "Could not destroy credentials - " + e.getMessage());
+            gssException.initCause(e);
+        }
+    }
+
+    // XXX call to this.destroy() should destroy the locally cached copy
+    // of krb5Credentials and then call super.destroy().
+
+    private static KerberosTicket getTgt(GSSCaller caller, Krb5NameElement name,
+                                                 int initLifetime)
+        throws GSSException {
+
+        final String clientPrincipal;
+
+        /*
+         * Find the TGT for the realm that the client is in. If the client
+         * name is not available, then use the default realm.
+         */
+        if (name != null) {
+            clientPrincipal = (name.getKrb5PrincipalName()).getName();
+        } else {
+            clientPrincipal = null;
+        }
+
+        final AccessControlContext acc = AccessController.getContext();
+
+        try {
+            final GSSCaller realCaller = (caller == GSSCaller.CALLER_UNKNOWN)
+                                   ? GSSCaller.CALLER_INITIATE
+                                   : caller;
+            return AccessController.doPrivileged(
+                new PrivilegedExceptionAction<KerberosTicket>() {
+                public KerberosTicket run() throws Exception {
+                    // It's OK to use null as serverPrincipal. TGT is almost
+                    // the first ticket for a principal and we use list.
+                    return Krb5Util.getTicket(
+                        realCaller,
+                        clientPrincipal, null, acc);
+                        }});
+        } catch (PrivilegedActionException e) {
+            GSSException ge =
+                new GSSException(GSSException.NO_CRED, -1,
+                    "Attempt to obtain new INITIATE credentials failed!" +
+                    " (" + e.getMessage() + ")");
+            ge.initCause(e.getException());
+            throw ge;
+        }
+    }
+
+    @Override
+    public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
+        try {
+            Krb5NameElement kname = (Krb5NameElement)name;
+            Credentials newCred = Credentials.acquireS4U2selfCreds(
+                    kname.getKrb5PrincipalName(), krb5Credentials);
+            return new Krb5ProxyCredential(this, kname, newCred.getTicket());
+        } catch (IOException | KrbException ke) {
+            GSSException ge =
+                new GSSException(GSSException.FAILURE, -1,
+                    "Attempt to obtain S4U2self credentials failed!");
+            ge.initCause(ke);
+            throw ge;
+        }
+    }
+}