/* * 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; } }