jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java
changeset 2 90ce3da70b43
child 2942 37d9baeb7518
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.jgss.krb5;
+
+import org.ietf.jgss.*;
+import sun.security.jgss.GSSUtil;
+import sun.security.jgss.spi.*;
+import javax.security.auth.kerberos.ServicePermission;
+import java.security.Provider;
+import sun.security.util.DerOutputStream;
+import sun.security.util.ObjectIdentifier;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * Krb5 Mechanism plug in for JGSS
+ * This is the properties object required by the JGSS framework.
+ * All mechanism specific information is defined here.
+ *
+ * @author Mayank Upadhyay
+ */
+
+public final class Krb5MechFactory implements MechanismFactory {
+
+    private static final boolean DEBUG = Krb5Util.DEBUG;
+
+    static final Provider PROVIDER =
+        new sun.security.jgss.SunProvider();
+
+    static final Oid GSS_KRB5_MECH_OID =
+        createOid("1.2.840.113554.1.2.2");
+
+    static final Oid NT_GSS_KRB5_PRINCIPAL =
+        createOid("1.2.840.113554.1.2.2.1");
+
+    private static Oid[] nameTypes =
+        new Oid[] { GSSName.NT_USER_NAME,
+                        GSSName.NT_HOSTBASED_SERVICE,
+                        GSSName.NT_EXPORT_NAME,
+                        NT_GSS_KRB5_PRINCIPAL};
+
+    final private int caller;
+
+    private static Krb5CredElement getCredFromSubject(GSSNameSpi name,
+                                                      boolean initiate)
+        throws GSSException {
+        Vector<Krb5CredElement> creds =
+            GSSUtil.searchSubject(name, GSS_KRB5_MECH_OID, initiate,
+                                  (initiate ?
+                                   Krb5InitCredential.class :
+                                   Krb5AcceptCredential.class));
+
+        Krb5CredElement result = ((creds == null || creds.isEmpty()) ?
+                                  null : creds.firstElement());
+
+        // Force permission check before returning the cred to caller
+        if (result != null) {
+            if (initiate) {
+                checkInitCredPermission((Krb5NameElement) result.getName());
+            } else {
+                checkAcceptCredPermission
+                    ((Krb5NameElement) result.getName(), name);
+            }
+        }
+        return result;
+    }
+
+    public Krb5MechFactory(int caller) {
+        this.caller = caller;
+    }
+
+    public GSSNameSpi getNameElement(String nameStr, Oid nameType)
+        throws GSSException {
+        return Krb5NameElement.getInstance(nameStr, nameType);
+    }
+
+    public GSSNameSpi getNameElement(byte[] name, Oid nameType)
+        throws GSSException {
+        // At this point, even an exported name is stripped down to safe
+        // bytes only
+        // XXX Use encoding here
+        return Krb5NameElement.getInstance(new String(name), nameType);
+    }
+
+    public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
+           int initLifetime, int acceptLifetime,
+           int usage) throws GSSException {
+
+        if (name != null && !(name instanceof Krb5NameElement)) {
+            name = Krb5NameElement.getInstance(name.toString(),
+                                       name.getStringNameType());
+        }
+
+        Krb5CredElement credElement = getCredFromSubject
+            (name, (usage != GSSCredential.ACCEPT_ONLY));
+
+        if (credElement == null) {
+            if (usage == GSSCredential.INITIATE_ONLY ||
+                usage == GSSCredential.INITIATE_AND_ACCEPT) {
+                credElement = Krb5InitCredential.getInstance
+                    (caller, (Krb5NameElement) name, initLifetime);
+                checkInitCredPermission
+                    ((Krb5NameElement) credElement.getName());
+            } else if (usage == GSSCredential.ACCEPT_ONLY) {
+                credElement =
+                    Krb5AcceptCredential.getInstance(caller,
+                                                     (Krb5NameElement) name);
+                checkAcceptCredPermission
+                    ((Krb5NameElement) credElement.getName(), name);
+            } else
+                throw new GSSException(GSSException.FAILURE, -1,
+                                       "Unknown usage mode requested");
+        }
+        return credElement;
+    }
+
+    public static void checkInitCredPermission(Krb5NameElement name) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            String realm = (name.getKrb5PrincipalName()).getRealmAsString();
+            String tgsPrincipal =
+                new String("krbtgt/" + realm + '@' + realm);
+            ServicePermission perm =
+                new ServicePermission(tgsPrincipal, "initiate");
+            try {
+                sm.checkPermission(perm);
+            } catch (SecurityException e) {
+                if (DEBUG) {
+                    System.out.println("Permission to initiate" +
+                        "kerberos init credential" + e.getMessage());
+                }
+                throw e;
+            }
+        }
+    }
+
+    public static void checkAcceptCredPermission(Krb5NameElement name,
+                                           GSSNameSpi originalName) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            ServicePermission perm = new ServicePermission
+                (name.getKrb5PrincipalName().getName(), "accept");
+            try {
+                sm.checkPermission(perm);
+            } catch (SecurityException e) {
+                if (originalName == null) {
+                    // Don't disclose the name of the principal
+                    e = new SecurityException("No permission to acquire "
+                                      + "Kerberos accept credential");
+                    // Don't call e.initCause() with caught exception
+                }
+                throw e;
+            }
+        }
+    }
+
+    public GSSContextSpi getMechanismContext(GSSNameSpi peer,
+                             GSSCredentialSpi myInitiatorCred, int lifetime)
+        throws GSSException {
+        if (peer != null && !(peer instanceof Krb5NameElement)) {
+            peer = Krb5NameElement.getInstance(peer.toString(),
+                                       peer.getStringNameType());
+        }
+        // XXX Convert myInitiatorCred to Krb5CredElement
+        if (myInitiatorCred == null) {
+            myInitiatorCred = getCredentialElement(null, lifetime, 0,
+                GSSCredential.INITIATE_ONLY);
+        }
+        return new Krb5Context(caller, (Krb5NameElement)peer,
+                               (Krb5CredElement)myInitiatorCred, lifetime);
+    }
+
+    public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
+        throws GSSException {
+        // XXX Convert myAcceptorCred to Krb5CredElement
+        if (myAcceptorCred == null) {
+            myAcceptorCred = getCredentialElement(null, 0,
+                GSSCredential.INDEFINITE_LIFETIME, GSSCredential.ACCEPT_ONLY);
+        }
+        return new Krb5Context(caller, (Krb5CredElement)myAcceptorCred);
+    }
+
+    public GSSContextSpi getMechanismContext(byte[] exportedContext)
+        throws GSSException {
+        return new Krb5Context(caller, exportedContext);
+    }
+
+
+    public final Oid getMechanismOid() {
+        return GSS_KRB5_MECH_OID;
+    }
+
+    public Provider getProvider() {
+        return PROVIDER;
+    }
+
+    public Oid[] getNameTypes() {
+        // nameTypes is cloned in GSSManager.getNamesForMech
+        return nameTypes;
+    }
+
+    private static Oid createOid(String oidStr) {
+        Oid retVal = null;
+        try {
+            retVal = new Oid(oidStr);
+        } catch (GSSException e) {
+            // Should not happen!
+        }
+        return retVal;
+    }
+}