407 lines
15 KiB
Java
407 lines
15 KiB
Java
/*
|
|
* Copyright (c) 2000, 2019, 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 sun.security.krb5.Config;
|
|
import javax.security.auth.kerberos.*;
|
|
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;
|
|
public KerberosTicket proxyTicket;
|
|
|
|
private Krb5InitCredential(Krb5NameElement name,
|
|
byte[] asn1Encoding,
|
|
KerberosPrincipal client,
|
|
KerberosPrincipal clientAlias,
|
|
KerberosPrincipal server,
|
|
KerberosPrincipal serverAlias,
|
|
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);
|
|
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
|
.kerberosTicketSetClientAlias(this, clientAlias);
|
|
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
|
.kerberosTicketSetServerAlias(this, serverAlias);
|
|
this.name = name;
|
|
|
|
try {
|
|
// Cache this for later use by the sun.security.krb5 package.
|
|
krb5Credentials = new Credentials(asn1Encoding,
|
|
client.getName(),
|
|
(clientAlias != null ?
|
|
clientAlias.getName() : null),
|
|
server.getName(),
|
|
(serverAlias != null ?
|
|
serverAlias.getName() : null),
|
|
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 clientAlias,
|
|
KerberosPrincipal server,
|
|
KerberosPrincipal serverAlias,
|
|
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);
|
|
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
|
.kerberosTicketSetClientAlias(this, clientAlias);
|
|
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
|
.kerberosTicketSetServerAlias(this, serverAlias);
|
|
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);
|
|
}
|
|
|
|
KerberosPrincipal clientAlias = KerberosSecrets
|
|
.getJavaxSecurityAuthKerberosAccess()
|
|
.kerberosTicketGetClientAlias(tgt);
|
|
KerberosPrincipal serverAlias = KerberosSecrets
|
|
.getJavaxSecurityAuthKerberosAccess()
|
|
.kerberosTicketGetServerAlias(tgt);
|
|
Krb5InitCredential result = new Krb5InitCredential(name,
|
|
tgt.getEncoded(),
|
|
tgt.getClient(),
|
|
clientAlias,
|
|
tgt.getServer(),
|
|
serverAlias,
|
|
tgt.getSessionKey().getEncoded(),
|
|
tgt.getSessionKeyType(),
|
|
tgt.getFlags(),
|
|
tgt.getAuthTime(),
|
|
tgt.getStartTime(),
|
|
tgt.getEndTime(),
|
|
tgt.getRenewTill(),
|
|
tgt.getClientAddresses());
|
|
result.proxyTicket = KerberosSecrets.getJavaxSecurityAuthKerberosAccess().
|
|
kerberosTicketGetProxy(tgt);
|
|
return result;
|
|
}
|
|
|
|
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 cAPrinc = delegatedCred.getClientAlias();
|
|
PrincipalName sPrinc = delegatedCred.getServer();
|
|
PrincipalName sAPrinc = delegatedCred.getServerAlias();
|
|
|
|
KerberosPrincipal client = null;
|
|
KerberosPrincipal clientAlias = null;
|
|
KerberosPrincipal server = null;
|
|
KerberosPrincipal serverAlias = null;
|
|
|
|
Krb5NameElement credName = null;
|
|
|
|
if (cPrinc != null) {
|
|
String fullName = cPrinc.getName();
|
|
credName = Krb5NameElement.getInstance(fullName,
|
|
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
|
|
client = new KerberosPrincipal(fullName);
|
|
}
|
|
|
|
if (cAPrinc != null) {
|
|
clientAlias = new KerberosPrincipal(cAPrinc.getName());
|
|
}
|
|
|
|
// XXX Compare name to credName
|
|
|
|
if (sPrinc != null) {
|
|
server =
|
|
new KerberosPrincipal(sPrinc.getName(),
|
|
KerberosPrincipal.KRB_NT_SRV_INST);
|
|
}
|
|
|
|
if (sAPrinc != null) {
|
|
serverAlias = new KerberosPrincipal(sAPrinc.getName());
|
|
}
|
|
|
|
return new Krb5InitCredential(credName,
|
|
delegatedCred,
|
|
delegatedCred.getEncoded(),
|
|
client,
|
|
clientAlias,
|
|
server,
|
|
serverAlias,
|
|
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 {
|
|
Date d = getEndTime();
|
|
if (d == null) {
|
|
return 0;
|
|
}
|
|
|
|
long retVal = d.getTime() - System.currentTimeMillis();
|
|
return (int)(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.getInitialTicket(
|
|
realCaller,
|
|
clientPrincipal, 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;
|
|
}
|
|
}
|
|
}
|