blob: d9552a1ec6aa4158707ea8b5dc56df2e083d4976 [file] [log] [blame]
/*
* Copyright (c) 2000, 2009, 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.GSSUtil;
import sun.security.jgss.GSSCaller;
import sun.security.jgss.spi.*;
import javax.security.auth.kerberos.ServicePermission;
import java.security.Provider;
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 GSSCaller 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(GSSCaller 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;
}
}