--- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Context.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Context.java Wed Nov 07 14:13:01 2012 +0800
@@ -45,6 +45,7 @@
import javax.crypto.Cipher;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.*;
+import sun.security.krb5.internal.Ticket;
/**
* Implements the mechanism specific context class for the Kerberos v5
@@ -76,7 +77,7 @@
* values.
*/
- private boolean credDelegState = false;
+ private boolean credDelegState = false; // now only useful at client
private boolean mutualAuthState = true;
private boolean replayDetState = true;
private boolean sequenceDetState = true;
@@ -84,6 +85,8 @@
private boolean integState = true;
private boolean delegPolicyState = false;
+ private boolean isConstrainedDelegationTried = false;
+
private int mySeqNumber;
private int peerSeqNumber;
private int keySrc;
@@ -113,13 +116,11 @@
private Krb5CredElement myCred;
private Krb5CredElement delegatedCred; // Set only on acceptor side
- /* DESCipher instance used by the corresponding GSSContext */
- private Cipher desCipher = null;
-
// XXX See if the required info from these can be extracted and
// stored elsewhere
private Credentials serviceCreds;
private KrbApReq apReq;
+ Ticket serviceTicket;
final private GSSCaller caller;
private static final boolean DEBUG = Krb5Util.DEBUG;
@@ -248,7 +249,14 @@
* Is credential delegation enabled?
*/
public final boolean getCredDelegState() {
- return credDelegState;
+ if (isInitiator()) {
+ return credDelegState;
+ } else {
+ // Server side deleg state is not flagged by credDelegState.
+ // It can use constrained delegation.
+ tryConstrainedDelegation();
+ return delegatedCred != null;
+ }
}
/**
@@ -498,7 +506,8 @@
* Returns the delegated credential for the context. This
* is an optional feature of contexts which not all
* mechanisms will support. A context can be requested to
- * support credential delegation by using the <b>CRED_DELEG</b>.
+ * support credential delegation by using the <b>CRED_DELEG</b>,
+ * or it can request for a constrained delegation.
* This is only valid on the acceptor side of the context.
* @return GSSCredentialSpi object for the delegated credential
* @exception GSSException
@@ -507,11 +516,41 @@
public final GSSCredentialSpi getDelegCred() throws GSSException {
if (state != STATE_IN_PROCESS && state != STATE_DONE)
throw new GSSException(GSSException.NO_CONTEXT);
- if (delegatedCred == null)
+ if (isInitiator()) {
throw new GSSException(GSSException.NO_CRED);
+ }
+ tryConstrainedDelegation();
+ if (delegatedCred == null) {
+ throw new GSSException(GSSException.NO_CRED);
+ }
return delegatedCred;
}
+ private void tryConstrainedDelegation() {
+ if (state != STATE_IN_PROCESS && state != STATE_DONE) {
+ return;
+ }
+ // We will only try constrained delegation once (if necessary).
+ if (!isConstrainedDelegationTried) {
+ if (delegatedCred == null) {
+ if (DEBUG) {
+ System.out.println(">>> Constrained deleg from " + caller);
+ }
+ // The constrained delegation part. The acceptor needs to have
+ // isInitiator=true in order to get a TGT, either earlier at
+ // logon stage, if useSubjectCredsOnly, or now.
+ try {
+ delegatedCred = new Krb5ProxyCredential(
+ Krb5InitCredential.getInstance(
+ GSSCaller.CALLER_ACCEPT, myName, lifetime),
+ peerName, serviceTicket);
+ } catch (GSSException gsse) {
+ // OK, delegatedCred is null then
+ }
+ }
+ isConstrainedDelegationTried = true;
+ }
+ }
/**
* Tests if this is the initiator side of the context.
*
@@ -577,8 +616,15 @@
"No TGT available");
}
myName = (Krb5NameElement) myCred.getName();
- Credentials tgt =
- ((Krb5InitCredential) myCred).getKrb5Credentials();
+ Credentials tgt;
+ final Krb5ProxyCredential second;
+ if (myCred instanceof Krb5InitCredential) {
+ second = null;
+ tgt = ((Krb5InitCredential) myCred).getKrb5Credentials();
+ } else {
+ second = (Krb5ProxyCredential) myCred;
+ tgt = second.self.getKrb5Credentials();
+ }
checkPermission(peerName.getKrb5PrincipalName().getName(),
"initiate");
@@ -607,7 +653,9 @@
GSSCaller.CALLER_UNKNOWN,
// since it's useSubjectCredsOnly here,
// don't worry about the null
- myName.getKrb5PrincipalName().getName(),
+ second == null ?
+ myName.getKrb5PrincipalName().getName():
+ second.getName().getKrb5PrincipalName().getName(),
peerName.getKrb5PrincipalName().getName(),
acc);
}});
@@ -638,9 +686,17 @@
"the subject");
}
// Get Service ticket using the Kerberos protocols
- serviceCreds = Credentials.acquireServiceCreds(
+ if (second == null) {
+ serviceCreds = Credentials.acquireServiceCreds(
peerName.getKrb5PrincipalName().getName(),
tgt);
+ } else {
+ serviceCreds = Credentials.acquireS4U2proxyCreds(
+ peerName.getKrb5PrincipalName().getName(),
+ second.tkt,
+ second.getName().getKrb5PrincipalName(),
+ tgt);
+ }
if (GSSUtil.useSubjectCredsOnly(caller)) {
final Subject subject =
AccessController.doPrivileged(
@@ -776,6 +832,7 @@
retVal = new AcceptSecContextToken(this,
token.getKrbApReq()).encode();
}
+ serviceTicket = token.getKrbApReq().getCreds().getTicket();
myCred = null;
state = STATE_DONE;
} else {
@@ -802,8 +859,6 @@
return retVal;
}
-
-
/**
* Queries the context for largest data size to accomodate
* the specified protection and be <= maxTokSize.