--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java Wed Nov 07 14:13:01 2012 +0800
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 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 com.sun.security.jgss;
+
+import org.ietf.jgss.*;
+
+/**
+ * The extended GSSCredential interface for supporting additional
+ * functionalities not defined by {@code org.ietf.jgss.GSSCredential}.
+ * @since 1.8
+ */
+public interface ExtendedGSSCredential extends GSSCredential {
+ /**
+ * Impersonates a principal. In Kerberos, this can be implemented
+ * using the Microsoft S4U2self extension.
+ * <p>
+ * A {@link GSSException#NO_CRED GSSException.NO_CRED} will be thrown if the
+ * impersonation fails. A {@link GSSException#FAILURE GSSException.FAILURE}
+ * will be thrown if the impersonation method is not available to this
+ * credential object.
+ * @param name the name of the principal to impersonate
+ * @return a credential for that principal
+ * @throws GSSException containing the following
+ * major error codes:
+ * {@link GSSException#NO_CRED GSSException.NO_CRED}
+ * {@link GSSException#FAILURE GSSException.FAILURE}
+ */
+ public GSSCredential impersonate(GSSName name) throws GSSException;
+}
--- a/jdk/src/share/classes/sun/security/jgss/GSSCaller.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/GSSCaller.java Wed Nov 07 14:13:01 2012 +0800
@@ -31,10 +31,19 @@
* different callers.
*/
public class GSSCaller {
- public static final GSSCaller CALLER_UNKNOWN = new GSSCaller();
- public static final GSSCaller CALLER_INITIATE = new GSSCaller();
- public static final GSSCaller CALLER_ACCEPT = new GSSCaller();
- public static final GSSCaller CALLER_SSL_CLIENT = new GSSCaller();
- public static final GSSCaller CALLER_SSL_SERVER = new GSSCaller();
+ public static final GSSCaller CALLER_UNKNOWN = new GSSCaller("UNKNOWN");
+ public static final GSSCaller CALLER_INITIATE = new GSSCaller("INITIATE");
+ public static final GSSCaller CALLER_ACCEPT = new GSSCaller("ACCEPT");
+ public static final GSSCaller CALLER_SSL_CLIENT = new GSSCaller("SSL_CLIENT");
+ public static final GSSCaller CALLER_SSL_SERVER = new GSSCaller("SSL_SERVER");
+
+ private String name;
+ GSSCaller(String s) {
+ name = s;
+ }
+ @Override
+ public String toString() {
+ return "GSSCaller{" + name + '}';
+ }
}
--- a/jdk/src/share/classes/sun/security/jgss/GSSCredentialImpl.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/GSSCredentialImpl.java Wed Nov 07 14:13:01 2012 +0800
@@ -28,8 +28,9 @@
import org.ietf.jgss.*;
import sun.security.jgss.spi.*;
import java.util.*;
+import com.sun.security.jgss.*;
-public class GSSCredentialImpl implements GSSCredential {
+public class GSSCredentialImpl implements ExtendedGSSCredential {
private GSSManagerImpl gssManager = null;
private boolean destroyed = false;
@@ -122,6 +123,19 @@
}
}
+ public GSSCredential impersonate(GSSName name) throws GSSException {
+ if (destroyed) {
+ throw new IllegalStateException("This credential is " +
+ "no longer valid");
+ }
+ Oid mech = tempCred.getMechanism();
+ GSSNameSpi nameElement = (name == null ? null :
+ ((GSSNameImpl)name).getElement(mech));
+ GSSCredentialSpi cred = tempCred.impersonate(nameElement);
+ return (cred == null ?
+ null : new GSSCredentialImpl(gssManager, cred));
+ }
+
public GSSName getName() throws GSSException {
if (destroyed) {
throw new IllegalStateException("This credential is " +
--- a/jdk/src/share/classes/sun/security/jgss/HttpCaller.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/HttpCaller.java Wed Nov 07 14:13:01 2012 +0800
@@ -35,6 +35,7 @@
final private HttpCallerInfo hci;
public HttpCaller(HttpCallerInfo hci) {
+ super("HTTP_CLIENT");
this.hci = hci;
}
--- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java Wed Nov 07 14:13:01 2012 +0800
@@ -25,6 +25,7 @@
package sun.security.jgss.krb5;
+import java.io.IOException;
import org.ietf.jgss.*;
import sun.security.jgss.GSSCaller;
import sun.security.jgss.spi.*;
@@ -177,4 +178,21 @@
public void destroy() throws DestroyFailedException {
screds.destroy();
}
+
+ /**
+ * Impersonation is only available on the initiator side. The
+ * service must starts as an initiator to get an initial TGT to complete
+ * the S4U2self protocol.
+ */
+ @Override
+ public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
+ Credentials cred = screds.getInitCred();
+ if (cred != null) {
+ return Krb5InitCredential.getInstance(this.name, cred)
+ .impersonate(name);
+ } else {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Only an initiate credentials can impersonate");
+ }
+ }
}
--- 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.
--- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java Wed Nov 07 14:13:01 2012 +0800
@@ -309,8 +309,7 @@
int initLifetime)
throws GSSException {
- String realm = null;
- final String clientPrincipal, tgsPrincipal = null;
+ final String clientPrincipal;
/*
* Find the TGT for the realm that the client is in. If the client
@@ -318,20 +317,8 @@
*/
if (name != null) {
clientPrincipal = (name.getKrb5PrincipalName()).getName();
- realm = (name.getKrb5PrincipalName()).getRealmAsString();
} else {
clientPrincipal = null;
- try {
- Config config = Config.getInstance();
- realm = config.getDefaultRealm();
- } catch (KrbException e) {
- GSSException ge =
- new GSSException(GSSException.NO_CRED, -1,
- "Attempt to obtain INITIATE credentials failed!" +
- " (" + e.getMessage() + ")");
- ge.initCause(e);
- throw ge;
- }
}
final AccessControlContext acc = AccessController.getContext();
@@ -343,9 +330,11 @@
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.getTicket(
realCaller,
- clientPrincipal, tgsPrincipal, acc);
+ clientPrincipal, null, acc);
}});
} catch (PrivilegedActionException e) {
GSSException ge =
@@ -356,4 +345,20 @@
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;
+ }
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5ProxyCredential.java Wed Nov 07 14:13:01 2012 +0800
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2012, 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.spi.*;
+import java.util.Date;
+import sun.security.krb5.internal.Ticket;
+
+/**
+ * Implements the krb5 proxy credential element used in constrained
+ * delegation. It is used in both impersonation (where there is no Kerberos 5
+ * communication between the middle server and the client) and normal
+ * constrained delegation (where there is, but client has not called
+ * requestCredDeleg(true)).
+ * @since 1.8
+ */
+
+public class Krb5ProxyCredential
+ implements Krb5CredElement {
+
+ public final Krb5InitCredential self; // the middle server
+ private final Krb5NameElement client; // the client
+
+ // The ticket with cname=client and sname=self. This can be a normal
+ // service ticket or an S4U2self ticket.
+ public final Ticket tkt;
+
+ Krb5ProxyCredential(Krb5InitCredential self, Krb5NameElement client,
+ Ticket tkt) {
+ this.self = self;
+ this.tkt = tkt;
+ this.client = client;
+ }
+
+ // The client name behind the proxy
+ @Override
+ public final Krb5NameElement getName() throws GSSException {
+ return client;
+ }
+
+ @Override
+ public int getInitLifetime() throws GSSException {
+ // endTime of tkt is not used by KDC, and it's also not
+ // available in the case of kerberos constr deleg
+ return self.getInitLifetime();
+ }
+
+ @Override
+ public int getAcceptLifetime() throws GSSException {
+ return 0;
+ }
+
+ @Override
+ public boolean isInitiatorCredential() throws GSSException {
+ return true;
+ }
+
+ @Override
+ public boolean isAcceptorCredential() throws GSSException {
+ return false;
+ }
+
+ @Override
+ public final Oid getMechanism() {
+ return Krb5MechFactory.GSS_KRB5_MECH_OID;
+ }
+
+ @Override
+ public final java.security.Provider getProvider() {
+ return Krb5MechFactory.PROVIDER;
+ }
+
+ @Override
+ public void dispose() throws GSSException {
+ try {
+ self.destroy();
+ } catch (javax.security.auth.DestroyFailedException e) {
+ GSSException gssException =
+ new GSSException(GSSException.FAILURE, -1,
+ "Could not destroy credentials - " + e.getMessage());
+ gssException.initCause(e);
+ }
+ }
+
+ @Override
+ public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
+ // Cannot impersonate multiple levels without the impersonatee's TGT.
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Only an initiate credentials can impersonate");
+ }
+}
--- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java Wed Nov 07 14:13:01 2012 +0800
@@ -206,7 +206,7 @@
* identity, which can be:
* 1. Some KerberosKeys (generated from password)
* 2. A KeyTab (for a typical service)
- * 3. A TGT (for a user2user service. Not supported yet)
+ * 3. A TGT (for S4U2proxy extension)
*
* Note that some creds can coexist. For example, a user2user service
* can use its keytab (or keys) if the client can successfully obtain a
@@ -219,7 +219,7 @@
private List<KeyTab> ktabs;
private List<KerberosKey> kk;
private Subject subj;
- //private KerberosTicket tgt; // user2user, not supported yet
+ private KerberosTicket tgt;
private static ServiceCreds getInstance(
Subject subj, String serverPrincipal) {
@@ -255,6 +255,8 @@
subj, null, null, KeyTab.class);
sc.kk = SubjectComber.findMany(
subj, serverPrincipal, null, KerberosKey.class);
+ sc.tgt = SubjectComber.find(subj, null, null, KerberosTicket.class);
+
if (sc.ktabs.isEmpty() && sc.kk.isEmpty()) {
return null;
}
@@ -310,10 +312,22 @@
return ekeys;
}
+ public Credentials getInitCred() {
+ if (tgt == null) {
+ return null;
+ }
+ try {
+ return ticketToCreds(tgt);
+ } catch (KrbException | IOException e) {
+ return null;
+ }
+ }
+
public void destroy() {
kp = null;
ktabs = null;
kk = null;
+ tgt = null;
}
}
/**
@@ -357,7 +371,7 @@
};
public static Credentials ticketToCreds(KerberosTicket kerbTicket)
- throws KrbException, IOException {
+ throws KrbException, IOException {
return new Credentials(
kerbTicket.getEncoded(),
kerbTicket.getClient().getName(),
--- a/jdk/src/share/classes/sun/security/jgss/spi/GSSCredentialSpi.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/spi/GSSCredentialSpi.java Wed Nov 07 14:13:01 2012 +0800
@@ -96,4 +96,13 @@
* @exception GSSException may be thrown
*/
public Oid getMechanism();
+
+ /**
+ * Impersonates another client.
+ *
+ * @param name the client to impersonate
+ * @return the new credential
+ * @exception GSSException may be thrown
+ */
+ public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException;
}
--- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java Wed Nov 07 14:13:01 2012 +0800
@@ -1059,6 +1059,9 @@
if (mechContext != null) {
GSSCredentialImpl delegCred =
(GSSCredentialImpl)mechContext.getDelegCred();
+ if (delegCred == null) {
+ return null;
+ }
// determine delegated cred element usage
boolean initiate = false;
if (delegCred.getUsage() == GSSCredential.INITIATE_ONLY) {
--- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoCredElement.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoCredElement.java Wed Nov 07 14:13:01 2012 +0800
@@ -88,4 +88,9 @@
public Oid getMechanism() {
return GSSUtil.GSS_SPNEGO_MECH_OID;
}
+
+ @Override
+ public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
+ return cred.impersonate(name);
+ }
}
--- a/jdk/src/share/classes/sun/security/jgss/wrapper/GSSCredElement.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/wrapper/GSSCredElement.java Wed Nov 07 14:13:01 2012 +0800
@@ -28,6 +28,7 @@
import java.security.Provider;
import sun.security.jgss.GSSUtil;
import sun.security.jgss.spi.GSSCredentialSpi;
+import sun.security.jgss.spi.GSSNameSpi;
/**
* This class is essentially a wrapper class for the gss_cred_id_t
@@ -132,4 +133,10 @@
protected void finalize() throws Throwable {
dispose();
}
+
+ @Override
+ public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "Not supported yet");
+ }
}
--- a/jdk/src/share/classes/sun/security/krb5/Credentials.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/Credentials.java Wed Nov 07 14:13:01 2012 +0800
@@ -449,6 +449,18 @@
return CredentialsUtil.acquireServiceCreds(service, ccreds);
}
+ public static Credentials acquireS4U2selfCreds(PrincipalName user,
+ Credentials ccreds) throws KrbException, IOException {
+ return CredentialsUtil.acquireS4U2selfCreds(user, ccreds);
+ }
+
+ public static Credentials acquireS4U2proxyCreds(String service,
+ Ticket second, PrincipalName client, Credentials ccreds)
+ throws KrbException, IOException {
+ return CredentialsUtil.acquireS4U2proxyCreds(
+ service, second, client, ccreds);
+ }
+
public CredentialsCache getCache() {
return cache;
}
@@ -490,18 +502,19 @@
public String toString() {
StringBuffer buffer = new StringBuffer("Credentials:");
- buffer.append("\nclient=").append(client);
- buffer.append("\nserver=").append(server);
+ buffer.append( "\n client=").append(client);
+ buffer.append( "\n server=").append(server);
if (authTime != null) {
- buffer.append("\nauthTime=").append(authTime);
+ buffer.append("\n authTime=").append(authTime);
}
if (startTime != null) {
- buffer.append("\nstartTime=").append(startTime);
+ buffer.append("\n startTime=").append(startTime);
}
- buffer.append("\nendTime=").append(endTime);
- buffer.append("\nrenewTill=").append(renewTill);
- buffer.append("\nflags: ").append(flags);
- buffer.append("\nEType (int): ").append(key.getEType());
+ buffer.append( "\n endTime=").append(endTime);
+ buffer.append( "\n renewTill=").append(renewTill);
+ buffer.append( "\n flags=").append(flags);
+ buffer.append( "\nEType (skey)=").append(key.getEType());
+ buffer.append( "\n (tkt key)=").append(ticket.encPart.eType);
return buffer.toString();
}
--- a/jdk/src/share/classes/sun/security/krb5/EncryptedData.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/EncryptedData.java Wed Nov 07 14:13:01 2012 +0800
@@ -160,8 +160,6 @@
kvno = key.getKeyVersionNumber();
}
*/
-
- // currently destructive on cipher
public byte[] decrypt(
EncryptionKey key, int usage)
throws KdcErrException, KrbApErrException, KrbCryptoException {
@@ -175,7 +173,9 @@
EType etypeEngine = EType.getInstance(eType);
plain = etypeEngine.decrypt(cipher, key.getBytes(), usage);
- cipher = null;
+ // The service ticket will be used in S4U2proxy request. Therefore
+ // the raw ticket is still needed.
+ //cipher = null;
return etypeEngine.decryptedData(plain);
}
--- a/jdk/src/share/classes/sun/security/krb5/KrbApReq.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/KrbApReq.java Wed Nov 07 14:13:01 2012 +0800
@@ -287,8 +287,9 @@
cusec = authenticator.cusec;
authenticator.ctime.setMicroSeconds(authenticator.cusec);
- if (!authenticator.cname.equals(enc_ticketPart.cname))
+ if (!authenticator.cname.equals(enc_ticketPart.cname)) {
throw new KrbApErrException(Krb5.KRB_AP_ERR_BADMATCH);
+ }
KerberosTime currTime = new KerberosTime(KerberosTime.NOW);
if (!authenticator.ctime.inClockSkew(currTime))
--- a/jdk/src/share/classes/sun/security/krb5/KrbKdcRep.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/KrbKdcRep.java Wed Nov 07 14:13:01 2012 +0800
@@ -64,7 +64,12 @@
for (int i = 1; i < 6; i++) {
if (req.reqBody.kdcOptions.get(i) !=
- rep.encKDCRepPart.flags.get(i)) {
+ rep.encKDCRepPart.flags.get(i)) {
+ if (Krb5.DEBUG) {
+ System.out.println("> KrbKdcRep.check: at #" + i
+ + ". request for " + req.reqBody.kdcOptions.get(i)
+ + ", received " + rep.encKDCRepPart.flags.get(i));
+ }
throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
}
}
--- a/jdk/src/share/classes/sun/security/krb5/KrbTgsRep.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/KrbTgsRep.java Wed Nov 07 14:13:01 2012 +0800
@@ -87,7 +87,7 @@
check(false, req, rep);
this.creds = new Credentials(rep.ticket,
- req.reqBody.cname,
+ rep.cname,
rep.ticket.sname,
enc_part.key,
enc_part.flags,
--- a/jdk/src/share/classes/sun/security/krb5/KrbTgsReq.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/KrbTgsReq.java Wed Nov 07 14:13:01 2012 +0800
@@ -35,6 +35,7 @@
import sun.security.krb5.internal.crypto.*;
import java.io.IOException;
import java.net.UnknownHostException;
+import java.util.Arrays;
/**
* This class encapsulates a Kerberos TGS-REQ that is sent from the
@@ -55,7 +56,7 @@
private byte[] obuf;
private byte[] ibuf;
- // Used in CredentialsUtil
+ // Used in CredentialsUtil
public KrbTgsReq(Credentials asCreds,
PrincipalName sname)
throws KrbException, IOException {
@@ -72,6 +73,45 @@
null); // EncryptionKey subSessionKey
}
+ // S4U2proxy
+ public KrbTgsReq(Credentials asCreds,
+ Ticket second,
+ PrincipalName sname)
+ throws KrbException, IOException {
+ this(KDCOptions.with(KDCOptions.CNAME_IN_ADDL_TKT,
+ KDCOptions.FORWARDABLE),
+ asCreds,
+ sname,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ new Ticket[] {second}, // the service ticket
+ null);
+ }
+
+ // S4U2user
+ public KrbTgsReq(Credentials asCreds,
+ PrincipalName sname,
+ PAData extraPA)
+ throws KrbException, IOException {
+ this(KDCOptions.with(KDCOptions.FORWARDABLE),
+ asCreds,
+ asCreds.getClient(),
+ sname,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ extraPA); // the PA-FOR-USER
+ }
+
// Called by Credentials, KrbCred
KrbTgsReq(
KDCOptions options,
@@ -85,14 +125,42 @@
AuthorizationData authorizationData,
Ticket[] additionalTickets,
EncryptionKey subKey) throws KrbException, IOException {
+ this(options, asCreds, asCreds.getClient(), sname,
+ from, till, rtime, eTypes, addresses,
+ authorizationData, additionalTickets, subKey, null);
+ }
- princName = asCreds.client;
+ private KrbTgsReq(
+ KDCOptions options,
+ Credentials asCreds,
+ PrincipalName cname,
+ PrincipalName sname,
+ KerberosTime from,
+ KerberosTime till,
+ KerberosTime rtime,
+ int[] eTypes,
+ HostAddresses addresses,
+ AuthorizationData authorizationData,
+ Ticket[] additionalTickets,
+ EncryptionKey subKey,
+ PAData extraPA) throws KrbException, IOException {
+
+ princName = cname;
servName = sname;
ctime = new KerberosTime(KerberosTime.NOW);
// check if they are valid arguments. The optional fields
// should be consistent with settings in KDCOptions.
+
+ // TODO: Is this necessary? If the TGT is not FORWARDABLE,
+ // you can still request for a FORWARDABLE ticket, just the
+ // KDC will give you a non-FORWARDABLE one. Even if you
+ // cannot use the ticket expected, it still contains info.
+ // This means there will be problem later. We already have
+ // flags check in KrbTgsRep. Of course, sometimes the KDC
+ // will not issue the ticket at all.
+
if (options.get(KDCOptions.FORWARDABLE) &&
(!(asCreds.flags.get(Krb5.TKT_OPTS_FORWARDABLE)))) {
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
@@ -130,13 +198,13 @@
} else {
if (rtime != null) rtime = null;
}
- if (options.get(KDCOptions.ENC_TKT_IN_SKEY)) {
+ if (options.get(KDCOptions.ENC_TKT_IN_SKEY) || options.get(KDCOptions.CNAME_IN_ADDL_TKT)) {
if (additionalTickets == null)
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
// in TGS_REQ there could be more than one additional
// tickets, but in file-based credential cache,
// there is only one additional ticket field.
- secondTicket = additionalTickets[0];
+ secondTicket = additionalTickets[0];
} else {
if (additionalTickets != null)
additionalTickets = null;
@@ -156,7 +224,8 @@
addresses,
authorizationData,
additionalTickets,
- subKey);
+ subKey,
+ extraPA);
obuf = tgsReqMessg.asn1Encode();
// XXX We need to revisit this to see if can't move it
@@ -221,7 +290,8 @@
HostAddresses addresses,
AuthorizationData authorizationData,
Ticket[] additionalTickets,
- EncryptionKey subKey)
+ EncryptionKey subKey,
+ PAData extraPA)
throws Asn1Exception, IOException, KdcErrException, KrbApErrException,
UnknownHostException, KrbCryptoException {
KerberosTime req_till = null;
@@ -318,10 +388,12 @@
null,
null).getMessage();
- PAData[] tgsPAData = new PAData[1];
- tgsPAData[0] = new PAData(Krb5.PA_TGS_REQ, tgs_ap_req);
-
- return new TGSReq(tgsPAData, reqBody);
+ PAData tgsPAData = new PAData(Krb5.PA_TGS_REQ, tgs_ap_req);
+ return new TGSReq(
+ extraPA != null ?
+ new PAData[] {extraPA, tgsPAData } :
+ new PAData[] {tgsPAData},
+ reqBody);
}
TGSReq getMessage() {
--- a/jdk/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java Wed Nov 07 14:13:01 2012 +0800
@@ -32,17 +32,7 @@
package sun.security.krb5.internal;
import sun.security.krb5.*;
-import sun.security.krb5.internal.ccache.CredentialsCache;
-import java.util.StringTokenizer;
-import sun.security.krb5.internal.ktab.*;
-import java.io.File;
import java.io.IOException;
-import java.util.Date;
-import java.util.Vector;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-import java.net.InetAddress;
/**
* This class is a utility that contains much of the TGS-Exchange
@@ -53,77 +43,158 @@
private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG;
- /**
- * Acquires credentials for a specified service using initial credential. Wh
-en the service has a different realm
- * from the initial credential, we do cross-realm authentication - first, we
- use the current credential to get
- * a cross-realm credential from the local KDC, then use that cross-realm cr
-edential to request service credential
- * from the foreigh KDC.
- *
- * @param service the name of service principal using format components@real
-m
- * @param ccreds client's initial credential.
- * @exception Exception general exception will be thrown when any error occu
-rs.
- * @return a <code>Credentials</code> object.
- */
+ /**
+ * Used by a middle server to acquire credentials on behalf of a
+ * client to itself using the S4U2self extension.
+ * @param client the client to impersonate
+ * @param ccreds the TGT of the middle service
+ * @return the new creds (cname=client, sname=middle)
+ */
+ public static Credentials acquireS4U2selfCreds(PrincipalName client,
+ Credentials ccreds) throws KrbException, IOException {
+ String uRealm = client.getRealmString();
+ String localRealm = ccreds.getClient().getRealmString();
+ if (!uRealm.equals(localRealm)) {
+ // TODO: we do not support kerberos referral now
+ throw new KrbException("Cross realm impersonation not supported");
+ }
+ KrbTgsReq req = new KrbTgsReq(
+ ccreds,
+ ccreds.getClient(),
+ new PAData(Krb5.PA_FOR_USER,
+ new PAForUserEnc(client,
+ ccreds.getSessionKey()).asn1Encode()));
+ Credentials creds = req.sendAndGetCreds();
+ if (!creds.getClient().equals(client)) {
+ throw new KrbException("S4U2self request not honored by KDC");
+ }
+ return creds;
+ }
+
+ /**
+ * Used by a middle server to acquire a service ticket to a backend
+ * server using the S4U2proxy extension.
+ * @param backend the name of the backend service
+ * @param second the client's service ticket to the middle server
+ * @param ccreds the TGT of the middle server
+ * @return the creds (cname=client, sname=backend)
+ */
+ public static Credentials acquireS4U2proxyCreds(
+ String backend, Ticket second,
+ PrincipalName client, Credentials ccreds)
+ throws KrbException, IOException {
+ KrbTgsReq req = new KrbTgsReq(
+ ccreds,
+ second,
+ new PrincipalName(backend));
+ Credentials creds = req.sendAndGetCreds();
+ if (!creds.getClient().equals(client)) {
+ throw new KrbException("S4U2proxy request not honored by KDC");
+ }
+ return creds;
+ }
+
+ /**
+ * Acquires credentials for a specified service using initial
+ * credential. When the service has a different realm from the initial
+ * credential, we do cross-realm authentication - first, we use the
+ * current credential to get a cross-realm credential from the local KDC,
+ * then use that cross-realm credential to request service credential
+ * from the foreign KDC.
+ *
+ * @param service the name of service principal
+ * @param ccreds client's initial credential
+ */
public static Credentials acquireServiceCreds(
String service, Credentials ccreds)
- throws KrbException, IOException {
+ throws KrbException, IOException {
PrincipalName sname = new PrincipalName(service);
String serviceRealm = sname.getRealmString();
String localRealm = ccreds.getClient().getRealmString();
- /*
- if (!localRealm.equalsIgnoreCase(serviceRealm)) { //do cross-realm auth entication
- if (DEBUG) {
- System.out.println(">>>DEBUG: Credentails request cross realm ticket for " + "krbtgt/" + serviceRealm + "@" + localRealm);
- }
- Credentials crossCreds = serviceCreds(new ServiceName("krbtgt/" + serviceRealm + "@" + localRealm), ccreds);
- if (DEBUG) {
- printDebug(crossCreds);
- }
- Credentials result = serviceCreds(sname, crossCreds);
- if (DEBUG) {
- printDebug(result);
- }
- return result;
- }
- else return serviceCreds(sname, ccreds);
- */
-
- if (localRealm.equals(serviceRealm))
- {
- if (DEBUG)
- System.out.println(">>> Credentials acquireServiceCreds: same realm");
+ if (localRealm.equals(serviceRealm)) {
+ if (DEBUG) {
+ System.out.println(
+ ">>> Credentials acquireServiceCreds: same realm");
+ }
return serviceCreds(sname, ccreds);
}
+ Credentials theCreds = null;
+
+ boolean[] okAsDelegate = new boolean[1];
+ Credentials theTgt = getTGTforRealm(localRealm, serviceRealm,
+ ccreds, okAsDelegate);
+ if (theTgt != null) {
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "got right tgt");
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "obtaining service creds for " + sname);
+ }
+
+ try {
+ theCreds = serviceCreds(sname, theTgt);
+ } catch (Exception exc) {
+ if (DEBUG) {
+ System.out.println(exc);
+ }
+ theCreds = null;
+ }
+ }
+
+ if (theCreds != null) {
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "returning creds:");
+ Credentials.printDebug(theCreds);
+ }
+ if (!okAsDelegate[0]) {
+ theCreds.resetDelegate();
+ }
+ return theCreds;
+ }
+ throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED,
+ "No service creds");
+ }
+
+ /**
+ * Gets a TGT to another realm
+ * @param localRealm this realm
+ * @param serviceRealm the other realm
+ * @param ccreds TGT in this realm
+ * @param okAsDelegate an [out] argument to receive the okAsDelegate
+ * property. True only if all realms allow delegation.
+ * @return the TGT for the other realm, null if cannot find a path
+ * @throws KrbException if something goes wrong
+ */
+ private static Credentials getTGTforRealm(String localRealm,
+ String serviceRealm, Credentials ccreds, boolean[] okAsDelegate)
+ throws KrbException {
// Get a list of realms to traverse
String[] realms = Realm.getRealmsList(localRealm, serviceRealm);
- boolean okAsDelegate = true;
- if (realms == null || realms.length == 0)
- {
- if (DEBUG)
- System.out.println(">>> Credentials acquireServiceCreds: no realms list");
+ if (realms == null || realms.length == 0) {
+ if (DEBUG) {
+ System.out.println(
+ ">>> Credentials acquireServiceCreds: no realms list");
+ }
return null;
}
int i = 0, k = 0;
Credentials cTgt = null, newTgt = null, theTgt = null;
PrincipalName tempService = null;
- String realm = null, newTgtRealm = null, theTgtRealm = null;
+ String newTgtRealm = null;
- for (cTgt = ccreds, i = 0; i < realms.length;)
- {
+ okAsDelegate[0] = true;
+ for (cTgt = ccreds, i = 0; i < realms.length;) {
tempService = PrincipalName.tgsService(serviceRealm, realms[i]);
- if (DEBUG)
- {
- System.out.println(">>> Credentials acquireServiceCreds: main loop: [" + i +"] tempService=" + tempService);
+ if (DEBUG) {
+ System.out.println(
+ ">>> Credentials acquireServiceCreds: main loop: ["
+ + i +"] tempService=" + tempService);
}
try {
@@ -132,11 +203,10 @@
newTgt = null;
}
- if (newTgt == null)
- {
- if (DEBUG)
- {
- System.out.println(">>> Credentials acquireServiceCreds: no tgt; searching backwards");
+ if (newTgt == null) {
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "no tgt; searching backwards");
}
/*
@@ -144,17 +214,15 @@
* realm as close to the target as possible.
* That means traversing the realms list backwards.
*/
-
for (newTgt = null, k = realms.length - 1;
- newTgt == null && k > i; k--)
- {
-
+ newTgt == null && k > i; k--) {
tempService = PrincipalName.tgsService(realms[k], realms[i]);
- if (DEBUG)
- {
- System.out.println(">>> Credentials acquireServiceCreds: inner loop: [" + k +"] tempService=" + tempService);
+ if (DEBUG) {
+ System.out.println(
+ ">>> Credentials acquireServiceCreds: "
+ + "inner loop: [" + k
+ + "] tempService=" + tempService);
}
-
try {
newTgt = serviceCreds(tempService, cTgt);
} catch (Exception exc) {
@@ -163,11 +231,10 @@
}
} // Ends 'if (newTgt == null)'
- if (newTgt == null)
- {
- if (DEBUG)
- {
- System.out.println(">>> Credentials acquireServiceCreds: no tgt; cannot get creds");
+ if (newTgt == null) {
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "no tgt; cannot get creds");
}
break;
}
@@ -176,29 +243,24 @@
* We have a tgt. It may or may not be for the target.
* If it's for the target realm, we're done looking for a tgt.
*/
-
newTgtRealm = newTgt.getServer().getInstanceComponent();
- if (okAsDelegate && !newTgt.checkDelegate()) {
- if (DEBUG)
- {
+ if (okAsDelegate[0] && !newTgt.checkDelegate()) {
+ if (DEBUG) {
System.out.println(">>> Credentials acquireServiceCreds: " +
"global OK-AS-DELEGATE turned off at " +
newTgt.getServer());
}
- okAsDelegate = false;
+ okAsDelegate[0] = false;
}
- if (DEBUG)
- {
- System.out.println(">>> Credentials acquireServiceCreds: got tgt");
- //printDebug(newTgt);
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "got tgt");
}
- if (newTgtRealm.equals(serviceRealm))
- {
+ if (newTgtRealm.equals(serviceRealm)) {
/* We got the right tgt */
theTgt = newTgt;
- theTgtRealm = newTgtRealm;
break;
}
@@ -207,17 +269,13 @@
* See if the realm of the new tgt is in the list of realms
* and continue looking from there.
*/
-
- for (k = i+1; k < realms.length; k++)
- {
- if (newTgtRealm.equals(realms[k]))
- {
+ for (k = i+1; k < realms.length; k++) {
+ if (newTgtRealm.equals(realms[k])) {
break;
}
}
- if (k < realms.length)
- {
+ if (k < realms.length) {
/*
* (re)set the counter so we start looking
* from the realm we just obtained a tgt for.
@@ -225,64 +283,24 @@
i = k;
cTgt = newTgt;
- if (DEBUG)
- {
- System.out.println(">>> Credentials acquireServiceCreds: continuing with main loop counter reset to " + i);
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "continuing with main loop counter reset to " + i);
}
-
continue;
}
- else
- {
+ else {
/*
* The new tgt's realm is not in the heirarchy of realms.
* It's probably not safe to get a tgt from
* a tgs that is outside the known list of realms.
* Give up now.
*/
-
break;
}
} // Ends outermost/main 'for' loop
- Credentials theCreds = null;
-
- if (theTgt != null)
- {
- /* We have the right tgt. Let's get the service creds */
-
- if (DEBUG)
- {
- System.out.println(">>> Credentials acquireServiceCreds: got right tgt");
-
- //printDebug(theTgt);
-
- System.out.println(">>> Credentials acquireServiceCreds: obtaining service creds for " + sname);
- }
-
- try {
- theCreds = serviceCreds(sname, theTgt);
- } catch (Exception exc) {
- if (DEBUG)
- System.out.println(exc);
- theCreds = null;
- }
- }
-
- if (theCreds != null)
- {
- if (DEBUG)
- {
- System.out.println(">>> Credentials acquireServiceCreds: returning creds:");
- Credentials.printDebug(theCreds);
- }
- if (!okAsDelegate) {
- theCreds.resetDelegate();
- }
- return theCreds;
- }
- throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED,
- "No service creds");
+ return theTgt;
}
/*
--- a/jdk/src/share/classes/sun/security/krb5/internal/EncKDCRepPart.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/EncKDCRepPart.java Wed Nov 07 14:13:01 2012 +0800
@@ -160,9 +160,10 @@
if (der.getData().available() > 0) {
caddr = HostAddresses.parse(der.getData(), (byte) 0x0B, true);
}
- if (der.getData().available() > 0) {
+ // We observe extra data from MSAD
+ /*if (der.getData().available() > 0) {
throw new Asn1Exception(Krb5.ASN1_BAD_ID);
- }
+ }*/
}
/**
--- a/jdk/src/share/classes/sun/security/krb5/internal/KDCOptions.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/KDCOptions.java Wed Nov 07 14:13:01 2012 +0800
@@ -139,13 +139,45 @@
public static final int UNUSED9 = 9;
public static final int UNUSED10 = 10;
public static final int UNUSED11 = 11;
+ public static final int CNAME_IN_ADDL_TKT = 14;
public static final int RENEWABLE_OK = 27;
public static final int ENC_TKT_IN_SKEY = 28;
public static final int RENEW = 30;
public static final int VALIDATE = 31;
+ private static final String[] names = {
+ "RESERVED", //0
+ "FORWARDABLE", //1;
+ "FORWARDED", //2;
+ "PROXIABLE", //3;
+ "PROXY", //4;
+ "ALLOW_POSTDATE", //5;
+ "POSTDATED", //6;
+ "UNUSED7", //7;
+ "RENEWABLE", //8;
+ "UNUSED9", //9;
+ "UNUSED10", //10;
+ "UNUSED11", //11;
+ null,null,
+ "CNAME_IN_ADDL_TKT",//14;
+ null,null,null,null,null,null,null,null,null,null,null,null,
+ "RENEWABLE_OK", //27;
+ "ENC_TKT_IN_SKEY", //28;
+ null,
+ "RENEW", //30;
+ "VALIDATE", //31;
+ };
+
private boolean DEBUG = Krb5.DEBUG;
+ public static KDCOptions with(int... flags) {
+ KDCOptions options = new KDCOptions();
+ for (int flag: flags) {
+ options.set(flag, true);
+ }
+ return options;
+ }
+
public KDCOptions() {
super(Krb5.KDC_OPTS_MAX + 1);
setDefault();
@@ -238,6 +270,20 @@
return super.get(option);
}
+ @Override public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("KDCOptions: ");
+ for (int i=0; i<Krb5.KDC_OPTS_MAX+1; i++) {
+ if (get(i)) {
+ if (names[i] != null) {
+ sb.append(names[i]).append(",");
+ } else {
+ sb.append(i).append(",");
+ }
+ }
+ }
+ return sb.toString();
+ }
private void setDefault() {
try {
--- a/jdk/src/share/classes/sun/security/krb5/internal/Krb5.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/Krb5.java Wed Nov 07 14:13:01 2012 +0800
@@ -158,6 +158,9 @@
public static final int PA_ETYPE_INFO = 11;
public static final int PA_ETYPE_INFO2 = 19;
+ // S4U2user info
+ public static final int PA_FOR_USER = 129;
+
//-------------------------------+-------------
//authorization data type |ad-type value
//-------------------------------+-------------
--- a/jdk/src/share/classes/sun/security/krb5/internal/PAData.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/PAData.java Wed Nov 07 14:13:01 2012 +0800
@@ -312,6 +312,9 @@
}
}
break;
+ case Krb5.PA_FOR_USER:
+ sb.append("\t PA-FOR-USER\n");
+ break;
default:
// Unknown Pre-auth type
break;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/krb5/internal/PAForUserEnc.java Wed Nov 07 14:13:01 2012 +0800
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2012, 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.krb5.internal;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import sun.security.krb5.*;
+import sun.security.krb5.internal.crypto.KeyUsage;
+import sun.security.krb5.internal.util.KerberosString;
+import sun.security.util.DerOutputStream;
+import sun.security.util.DerValue;
+
+/**
+ * Implements the ASN.1 PA-FOR-USER type.
+ *
+ * <xmp>
+ * padata-type ::= PA-FOR-USER
+ * -- value 129
+ * padata-value ::= EncryptedData
+ * -- PA-FOR-USER-ENC
+ * PA-FOR-USER-ENC ::= SEQUENCE {
+ * userName[0] PrincipalName,
+ * userRealm[1] Realm,
+ * cksum[2] Checksum,
+ * auth-package[3] KerberosString
+ * }
+ * </xmp>
+ *
+ * <p>
+ * This definition reflects MS-SFU.
+ */
+
+public class PAForUserEnc {
+ final public PrincipalName name;
+ final private EncryptionKey key;
+ final public static String AUTH_PACKAGE = "Kerberos";
+
+ public PAForUserEnc(PrincipalName name, EncryptionKey key) {
+ this.name = name;
+ this.key = key;
+ }
+
+ /**
+ * Constructs a PA-FOR-USER object from a DER encoding.
+ * @param encoding the input object
+ * @param key the key to verify the checksum inside encoding
+ * @throws KrbException if the verification fails.
+ * Note: this method is now only used by test KDC, therefore
+ * the verification is ignored (at the moment).
+ */
+ public PAForUserEnc(DerValue encoding, EncryptionKey key)
+ throws Asn1Exception, KrbException, IOException {
+ DerValue der = null;
+ this.key = key;
+
+ if (encoding.getTag() != DerValue.tag_Sequence) {
+ throw new Asn1Exception(Krb5.ASN1_BAD_ID);
+ }
+
+ // Realm after name? Quite abnormal.
+ PrincipalName tmpName = null;
+ der = encoding.getData().getDerValue();
+ if ((der.getTag() & 0x1F) == 0x00) {
+ try {
+ tmpName = new PrincipalName(der.getData().getDerValue(),
+ new Realm("PLACEHOLDER"));
+ } catch (RealmException re) {
+ // Impossible
+ }
+ } else {
+ throw new Asn1Exception(Krb5.ASN1_BAD_ID);
+ }
+
+ der = encoding.getData().getDerValue();
+ if ((der.getTag() & 0x1F) == 0x01) {
+ try {
+ Realm realm = new Realm(der.getData().getDerValue());
+ name = new PrincipalName(
+ tmpName.getNameType(), tmpName.getNameStrings(), realm);
+ } catch (RealmException re) {
+ throw new IOException(re);
+ }
+ } else {
+ throw new Asn1Exception(Krb5.ASN1_BAD_ID);
+ }
+
+ der = encoding.getData().getDerValue();
+ if ((der.getTag() & 0x1F) == 0x02) {
+ // Deal with the checksum
+ } else {
+ throw new Asn1Exception(Krb5.ASN1_BAD_ID);
+ }
+
+ der = encoding.getData().getDerValue();
+ if ((der.getTag() & 0x1F) == 0x03) {
+ String authPackage = new KerberosString(der.getData().getDerValue()).toString();
+ if (!authPackage.equalsIgnoreCase(AUTH_PACKAGE)) {
+ throw new IOException("Incorrect auth-package");
+ }
+ } else {
+ throw new Asn1Exception(Krb5.ASN1_BAD_ID);
+ }
+ if (encoding.getData().available() > 0)
+ throw new Asn1Exception(Krb5.ASN1_BAD_ID);
+ }
+
+ public byte[] asn1Encode() throws Asn1Exception, IOException {
+ DerOutputStream bytes = new DerOutputStream();
+ bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), name.asn1Encode());
+ bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), name.getRealm().asn1Encode());
+
+ try {
+ Checksum cks = new Checksum(
+ Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR,
+ getS4UByteArray(),
+ key,
+ KeyUsage.KU_PA_FOR_USER_ENC_CKSUM);
+ bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x02), cks.asn1Encode());
+ } catch (KrbException ke) {
+ throw new IOException(ke);
+ }
+
+ DerOutputStream temp = new DerOutputStream();
+ temp.putDerValue(new KerberosString(AUTH_PACKAGE).toDerValue());
+ bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x03), temp);
+
+ temp = new DerOutputStream();
+ temp.write(DerValue.tag_Sequence, bytes);
+ return temp.toByteArray();
+ }
+
+ /**
+ * Returns S4UByteArray, the block to calculate checksum inside a
+ * PA-FOR-USER-ENC data structure. It includes:
+ * 1. userName.name-type encoded as a 4-byte integer in little endian
+ * byte order
+ * 2. all string values in the sequence of strings contained in the
+ * userName.name-string field
+ * 3. the string value of the userRealm field
+ * 4. the string value of auth-package field
+ */
+ public byte[] getS4UByteArray() {
+ try {
+ ByteArrayOutputStream ba = new ByteArrayOutputStream();
+ ba.write(new byte[4]);
+ for (String s: name.getNameStrings()) {
+ ba.write(s.getBytes("UTF-8"));
+ }
+ ba.write(name.getRealm().toString().getBytes("UTF-8"));
+ ba.write(AUTH_PACKAGE.getBytes("UTF-8"));
+ byte[] output = ba.toByteArray();
+ int pnType = name.getNameType();
+ output[0] = (byte)(pnType & 0xff);
+ output[1] = (byte)((pnType>>8) & 0xff);
+ output[2] = (byte)((pnType>>16) & 0xff);
+ output[3] = (byte)((pnType>>24) & 0xff);
+ return output;
+ } catch (IOException ioe) {
+ // not possible
+ throw new AssertionError("Cannot write ByteArrayOutputStream", ioe);
+ }
+ }
+
+ public String toString() {
+ return "PA-FOR-USER: " + name;
+ }
+}
--- a/jdk/src/share/classes/sun/security/krb5/internal/crypto/KeyUsage.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/crypto/KeyUsage.java Wed Nov 07 14:13:01 2012 +0800
@@ -54,6 +54,7 @@
public static final int KU_ENC_KRB_PRIV_PART = 13; // KrbPriv
public static final int KU_ENC_KRB_CRED_PART = 14; // KrbCred
public static final int KU_KRB_SAFE_CKSUM = 15; // KrbSafe
+ public static final int KU_PA_FOR_USER_ENC_CKSUM = 17; // S4U2user
public static final int KU_AD_KDC_ISSUED_CKSUM = 19;
public static final boolean isValid(int usage) {
--- a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java Wed Nov 07 14:13:01 2012 +0800
@@ -279,6 +279,9 @@
EncryptionKey key;
int size = entries.size();
ArrayList<EncryptionKey> keys = new ArrayList<>(size);
+ if (DEBUG) {
+ System.out.println("Looking for keys for: " + service);
+ }
for (int i = size-1; i >= 0; i--) {
entry = entries.elementAt(i);
if (entry.service.match(service)) {
--- a/jdk/test/sun/security/krb5/auto/Basic.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/test/sun/security/krb5/auto/Basic.java Wed Nov 07 14:13:01 2012 +0800
@@ -38,11 +38,13 @@
new OneKDC(null).writeJAASConf();
- Context c, s;
+ Context c, s, s2, b;
c = Context.fromJAAS("client");
s = Context.fromJAAS("server");
+ b = Context.fromJAAS("backend");
c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+ c.x().requestCredDeleg(true);
s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
Context.handshake(c, s);
@@ -50,7 +52,13 @@
Context.transmit("i say high --", c, s);
Context.transmit(" you say low", s, c);
+ s2 = s.delegated();
s.dispose();
c.dispose();
+
+ s2.startAsClient(OneKDC.BACKEND, GSSUtil.GSS_KRB5_MECH_OID);
+ b.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
+
+ Context.handshake(s2, b);
}
}
--- a/jdk/test/sun/security/krb5/auto/Context.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/test/sun/security/krb5/auto/Context.java Wed Nov 07 14:13:01 2012 +0800
@@ -42,9 +42,10 @@
import com.sun.security.jgss.ExtendedGSSContext;
import com.sun.security.jgss.InquireType;
import com.sun.security.jgss.AuthorizationDataEntry;
+import com.sun.security.jgss.ExtendedGSSCredential;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import javax.security.auth.kerberos.KeyTab;
+import java.security.Principal;
/**
* Context of a JGSS subject, encapsulating Subject and GSSContext.
@@ -90,7 +91,21 @@
public Context delegated() throws Exception {
Context out = new Context();
out.s = s;
- out.cred = x.getDelegCred();
+ try {
+ out.cred = Subject.doAs(s, new PrivilegedExceptionAction<GSSCredential>() {
+ @Override
+ public GSSCredential run() throws Exception {
+ GSSCredential cred = x.getDelegCred();
+ if (cred == null && x.getCredDelegState() ||
+ cred != null && !x.getCredDelegState()) {
+ throw new Exception("getCredDelegState not match");
+ }
+ return cred;
+ }
+ });
+ } catch (PrivilegedActionException pae) {
+ throw pae.getException();
+ }
out.name = name + " as " + out.cred.getName().toString();
return out;
}
@@ -212,28 +227,34 @@
* @throws java.lang.Exception
*/
public void startAsServer(final Oid mech) throws Exception {
- startAsServer(null, mech);
+ startAsServer(null, mech, false);
}
+ public void startAsServer(final String name, final Oid mech) throws Exception {
+ startAsServer(name, mech, false);
+ }
/**
* Starts as a server with the specified service name
* @param name the service name
* @param mech GSS mech
* @throws java.lang.Exception
*/
- public void startAsServer(final String name, final Oid mech) throws Exception {
+ public void startAsServer(final String name, final Oid mech, final boolean asInitiator) throws Exception {
doAs(new Action() {
@Override
public byte[] run(Context me, byte[] dummy) throws Exception {
GSSManager m = GSSManager.getInstance();
- me.x = (ExtendedGSSContext)m.createContext(m.createCredential(
+ me.cred = m.createCredential(
name == null ? null :
(name.indexOf('@') < 0 ?
m.createName(name, null) :
m.createName(name, GSSName.NT_HOSTBASED_SERVICE)),
GSSCredential.INDEFINITE_LIFETIME,
mech,
- GSSCredential.ACCEPT_ONLY));
+ asInitiator?
+ GSSCredential.INITIATE_AND_ACCEPT:
+ GSSCredential.ACCEPT_ONLY);
+ me.x = (ExtendedGSSContext)m.createContext(me.cred);
return null;
}
}, null);
@@ -331,27 +352,38 @@
} catch (Exception e) {
;// Don't care
}
- System.out.println("====== Private Credentials Set ======");
- for (Object o : s.getPrivateCredentials()) {
- System.out.println(" " + o.getClass());
- if (o instanceof KerberosTicket) {
- KerberosTicket kt = (KerberosTicket) o;
- System.out.println(" " + kt.getServer() + " for " + kt.getClient());
- } else if (o instanceof KerberosKey) {
- KerberosKey kk = (KerberosKey) o;
- System.out.print(" " + kk.getKeyType() + " " + kk.getVersionNumber() + " " + kk.getAlgorithm() + " ");
- for (byte b : kk.getEncoded()) {
- System.out.printf("%02X", b & 0xff);
- }
- System.out.println();
- } else if (o instanceof Map) {
- Map map = (Map) o;
- for (Object k : map.keySet()) {
- System.out.println(" " + k + ": " + map.get(k));
- }
- } else {
+ if (s != null) {
+ System.out.println("====== START SUBJECT CONTENT =====");
+ for (Principal p: s.getPrincipals()) {
+ System.out.println(" Principal: " + p);
+ }
+ for (Object o : s.getPublicCredentials()) {
+ System.out.println(" " + o.getClass());
System.out.println(" " + o);
}
+ System.out.println("====== Private Credentials Set ======");
+ for (Object o : s.getPrivateCredentials()) {
+ System.out.println(" " + o.getClass());
+ if (o instanceof KerberosTicket) {
+ KerberosTicket kt = (KerberosTicket) o;
+ System.out.println(" " + kt.getServer() + " for " + kt.getClient());
+ } else if (o instanceof KerberosKey) {
+ KerberosKey kk = (KerberosKey) o;
+ System.out.print(" " + kk.getKeyType() + " " + kk.getVersionNumber() + " " + kk.getAlgorithm() + " ");
+ for (byte b : kk.getEncoded()) {
+ System.out.printf("%02X", b & 0xff);
+ }
+ System.out.println();
+ } else if (o instanceof Map) {
+ Map map = (Map) o;
+ for (Object k : map.keySet()) {
+ System.out.println(" " + k + ": " + map.get(k));
+ }
+ } else {
+ System.out.println(" " + o);
+ }
+ }
+ System.out.println("====== END SUBJECT CONTENT =====");
}
if (x != null && x instanceof ExtendedGSSContext) {
if (x.isEstablished()) {
@@ -510,6 +542,29 @@
return sb.toString();
}
+ public Context impersonate(final String someone) throws Exception {
+ try {
+ GSSCredential creds = Subject.doAs(s, new PrivilegedExceptionAction<GSSCredential>() {
+ @Override
+ public GSSCredential run() throws Exception {
+ GSSManager m = GSSManager.getInstance();
+ GSSName other = m.createName(someone, GSSName.NT_USER_NAME);
+ if (Context.this.cred == null) {
+ Context.this.cred = m.createCredential(GSSCredential.INITIATE_ONLY);
+ }
+ return ((ExtendedGSSCredential)Context.this.cred).impersonate(other);
+ }
+ });
+ Context out = new Context();
+ out.s = s;
+ out.cred = creds;
+ out.name = name + " as " + out.cred.getName().toString();
+ return out;
+ } catch (PrivilegedActionException pae) {
+ throw pae.getException();
+ }
+ }
+
public byte[] take(final byte[] in) throws Exception {
return doAs(new Action() {
@Override
@@ -522,10 +577,11 @@
}
return null;
} else {
- System.out.println(name + " call initSecContext");
if (me.x.isInitiator()) {
+ System.out.println(name + " call initSecContext");
return me.x.initSecContext(input, 0, input.length);
} else {
+ System.out.println(name + " call acceptSecContext");
return me.x.acceptSecContext(input, 0, input.length);
}
}
--- a/jdk/test/sun/security/krb5/auto/CrossRealm.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/test/sun/security/krb5/auto/CrossRealm.java Wed Nov 07 14:13:01 2012 +0800
@@ -24,6 +24,7 @@
/*
* @test
* @bug 6706974
+ * @compile -XDignore.symbol.file CrossRealm.java
* @run main/othervm CrossRealm
* @summary Add krb5 test infrastructure
*/
--- a/jdk/test/sun/security/krb5/auto/KDC.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/test/sun/security/krb5/auto/KDC.java Wed Nov 07 14:13:01 2012 +0800
@@ -178,6 +178,20 @@
* What backend server can be delegated to
*/
OK_AS_DELEGATE,
+ /**
+ * Allow S4U2self, List<String> of middle servers.
+ * If not set, means KDC does not understand S4U2self at all, therefore
+ * would ignore any PA-FOR-USER request and send a ticket using the
+ * cname of teh requestor. If set, it returns FORWARDABLE tickets to
+ * a server with its name in the list
+ */
+ ALLOW_S4U2SELF,
+ /**
+ * Allow S4U2proxy, Map<String,List<String>> of middle servers to
+ * backends. If not set or a backend not in a server's list,
+ * Krb5.KDC_ERR_POLICY will be send for S4U2proxy request.
+ */
+ ALLOW_S4U2PROXY,
};
static {
@@ -618,13 +632,18 @@
int e2 = eTypes[0]; // etype for outgoing session key
int e3 = eTypes[0]; // etype for outgoing ticket
- PAData[] pas = kDCReqDotPAData(tgsReq);
+ PAData[] pas = KDCReqDotPAData(tgsReq);
Ticket tkt = null;
EncTicketPart etp = null;
+
+ PrincipalName cname = null;
+ boolean allowForwardable = true;
+
if (pas == null || pas.length == 0) {
throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP);
} else {
+ PrincipalName forUserCName = null;
for (PAData pa: pas) {
if (pa.getType() == Krb5.PA_TGS_REQ) {
APReq apReq = new APReq(pa.getValue());
@@ -636,8 +655,31 @@
DerInputStream derIn = new DerInputStream(bb);
DerValue der = derIn.getDerValue();
etp = new EncTicketPart(der.toByteArray());
+ // Finally, cname will be overwritten by PA-FOR-USER
+ // if it exists.
+ cname = etp.cname;
+ System.out.println(realm + "> presenting a ticket of "
+ + etp.cname + " to " + tkt.sname);
+ } else if (pa.getType() == Krb5.PA_FOR_USER) {
+ if (options.containsKey(Option.ALLOW_S4U2SELF)) {
+ PAForUserEnc p4u = new PAForUserEnc(
+ new DerValue(pa.getValue()), null);
+ forUserCName = p4u.name;
+ System.out.println(realm + "> presenting a PA_FOR_USER "
+ + " in the name of " + p4u.name);
+ }
}
}
+ if (forUserCName != null) {
+ List<String> names = (List<String>)options.get(Option.ALLOW_S4U2SELF);
+ if (!names.contains(cname.toString())) {
+ // Mimic the normal KDC behavior. When a server is not
+ // allowed to send S4U2self, do not send an error.
+ // Instead, send a ticket which is useless later.
+ allowForwardable = false;
+ }
+ cname = forUserCName;
+ }
if (tkt == null) {
throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP);
}
@@ -658,7 +700,8 @@
}
boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1];
- if (body.kdcOptions.get(KDCOptions.FORWARDABLE)) {
+ if (body.kdcOptions.get(KDCOptions.FORWARDABLE)
+ && allowForwardable) {
bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true;
}
if (body.kdcOptions.get(KDCOptions.FORWARDED) ||
@@ -678,6 +721,37 @@
if (body.kdcOptions.get(KDCOptions.ALLOW_POSTDATE)) {
bFlags[Krb5.TKT_OPTS_MAY_POSTDATE] = true;
}
+ if (body.kdcOptions.get(KDCOptions.CNAME_IN_ADDL_TKT)) {
+ if (!options.containsKey(Option.ALLOW_S4U2PROXY)) {
+ // Don't understand CNAME_IN_ADDL_TKT
+ throw new KrbException(Krb5.KDC_ERR_BADOPTION);
+ } else {
+ Map<String,List<String>> map = (Map<String,List<String>>)
+ options.get(Option.ALLOW_S4U2PROXY);
+ Ticket second = KDCReqBodyDotFirstAdditionalTicket(body);
+ EncryptionKey key2 = keyForUser(second.sname, second.encPart.getEType(), true);
+ byte[] bb = second.encPart.decrypt(key2, KeyUsage.KU_TICKET);
+ DerInputStream derIn = new DerInputStream(bb);
+ DerValue der = derIn.getDerValue();
+ EncTicketPart tktEncPart = new EncTicketPart(der.toByteArray());
+ if (!tktEncPart.flags.get(Krb5.TKT_OPTS_FORWARDABLE)) {
+ //throw new KrbException(Krb5.KDC_ERR_BADOPTION);
+ }
+ PrincipalName client = tktEncPart.cname;
+ System.out.println(realm + "> and an additional ticket of "
+ + client + " to " + second.sname);
+ if (map.containsKey(cname.toString())) {
+ if (map.get(cname.toString()).contains(service.toString())) {
+ System.out.println(realm + "> S4U2proxy OK");
+ } else {
+ throw new KrbException(Krb5.KDC_ERR_BADOPTION);
+ }
+ } else {
+ throw new KrbException(Krb5.KDC_ERR_BADOPTION);
+ }
+ cname = client;
+ }
+ }
String okAsDelegate = (String)options.get(Option.OK_AS_DELEGATE);
if (okAsDelegate != null && (
@@ -691,7 +765,7 @@
EncTicketPart enc = new EncTicketPart(
tFlags,
key,
- etp.cname,
+ cname,
new TransitedEncoding(1, new byte[0]), // TODO
new KerberosTime(new Date()),
body.from,
@@ -729,7 +803,7 @@
);
EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY);
TGSRep tgsRep = new TGSRep(null,
- etp.cname,
+ cname,
t,
edata);
System.out.println(" Return " + tgsRep.cname
@@ -942,7 +1016,7 @@
outPAs.add(new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray()));
}
- PAData[] inPAs = kDCReqDotPAData(asReq);
+ PAData[] inPAs = KDCReqDotPAData(asReq);
if (inPAs == null || inPAs.length == 0) {
Object preauth = options.get(Option.PREAUTH_REQUIRED);
if (preauth == null || preauth.equals(Boolean.TRUE)) {
@@ -1252,6 +1326,7 @@
private static final Field getEType;
private static final Constructor<EncryptedData> ctorEncryptedData;
private static final Method stringToKey;
+ private static final Field getAddlTkt;
static {
try {
@@ -1265,6 +1340,8 @@
"stringToKey",
char[].class, String.class, byte[].class, Integer.TYPE);
stringToKey.setAccessible(true);
+ getAddlTkt = KDCReqBody.class.getDeclaredField("additionalTickets");
+ getAddlTkt.setAccessible(true);
} catch (NoSuchFieldException nsfe) {
throw new AssertionError(nsfe);
} catch (NoSuchMethodException nsme) {
@@ -1278,7 +1355,7 @@
throw new AssertionError(e);
}
}
- private static PAData[] kDCReqDotPAData(KDCReq req) {
+ private static PAData[] KDCReqDotPAData(KDCReq req) {
try {
return (PAData[])getPADataField.get(req);
} catch (Exception e) {
@@ -1303,4 +1380,11 @@
throw new AssertionError(e);
}
}
+ private static Ticket KDCReqBodyDotFirstAdditionalTicket(KDCReqBody body) {
+ try {
+ return ((Ticket[])getAddlTkt.get(body))[0];
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
}
--- a/jdk/test/sun/security/krb5/auto/OkAsDelegate.java Tue Nov 06 18:41:01 2012 -0800
+++ b/jdk/test/sun/security/krb5/auto/OkAsDelegate.java Wed Nov 07 14:13:01 2012 +0800
@@ -91,7 +91,7 @@
Context c, s;
c = Context.fromJAAS("client");
- s = Context.fromJAAS("server");
+ s = Context.fromJAAS("com.sun.security.jgss.krb5.accept");
Oid mech = GSSUtil.GSS_KRB5_MECH_OID;
if (System.getProperty("test.spnego") != null) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/S4U2proxy.java Wed Nov 07 14:13:01 2012 +0800
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6355584
+ * @summary Introduce constrained Kerberos delegation
+ * @compile -XDignore.symbol.file S4U2proxy.java
+ * @run main/othervm S4U2proxy krb5
+ * @run main/othervm S4U2proxy spnego
+ */
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSUtil;
+
+public class S4U2proxy {
+
+ public static void main(String[] args) throws Exception {
+ Oid mech;
+ if (args[0].equals("spnego")) {
+ mech = GSSUtil.GSS_SPNEGO_MECH_OID;
+ } else if (args[0].contains("krb5")) {
+ mech = GSSUtil.GSS_KRB5_MECH_OID;
+ } else {
+ throw new Exception("Unknown mech");
+ }
+
+ OneKDC kdc = new OneKDC(null);
+ kdc.writeJAASConf();
+ kdc.setOption(KDC.Option.PREAUTH_REQUIRED, false);
+ Map<String,List<String>> map = new HashMap<>();
+ map.put(OneKDC.SERVER + "@" + OneKDC.REALM, Arrays.asList(
+ new String[]{OneKDC.BACKEND + "@" + OneKDC.REALM}));
+ kdc.setOption(KDC.Option.ALLOW_S4U2PROXY, map);
+
+ Context c, s, b;
+ c = Context.fromJAAS("client");
+ s = Context.fromJAAS("server");
+ b = Context.fromJAAS("backend");
+
+ c.startAsClient(OneKDC.SERVER, mech);
+ s.startAsServer(null, mech, false);
+
+ Context.handshake(c, s);
+ Context p = s.delegated();
+
+ p.startAsClient(OneKDC.BACKEND, mech);
+ b.startAsServer(mech);
+ Context.handshake(p, b);
+
+ p.startAsClient(OneKDC.BACKEND, mech);
+ b.startAsServer(mech);
+ Context.handshake(p, b);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/S4U2proxyGSS.java Wed Nov 07 14:13:01 2012 +0800
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6355584
+ * @summary Introduce constrained Kerberos delegation
+ * @compile -XDignore.symbol.file S4U2proxyGSS.java
+ * @run main/othervm -Djavax.security.auth.useSubjectCredsOnly=false S4U2proxyGSS krb5
+ * @run main/othervm -Djavax.security.auth.useSubjectCredsOnly=false S4U2proxyGSS spnego
+ */
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSUtil;
+
+public class S4U2proxyGSS {
+
+ public static void main(String[] args) throws Exception {
+ Oid mech;
+ if (args[0].equals("spnego")) {
+ mech = GSSUtil.GSS_SPNEGO_MECH_OID;
+ } else if (args[0].contains("krb5")) {
+ mech = GSSUtil.GSS_KRB5_MECH_OID;
+ } else {
+ throw new Exception("Unknown mech");
+ }
+
+ OneKDC kdc = new OneKDC(null);
+ kdc.writeJAASConf();
+ kdc.setOption(KDC.Option.PREAUTH_REQUIRED, false);
+ Map<String,List<String>> map = new HashMap<>();
+ map.put(OneKDC.SERVER + "@" + OneKDC.REALM, Arrays.asList(
+ new String[]{OneKDC.SERVER + "@" + OneKDC.REALM}));
+ kdc.setOption(KDC.Option.ALLOW_S4U2PROXY, map);
+
+ Context c, s, b;
+ System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
+ System.setProperty("java.security.auth.login.config", OneKDC.JAAS_CONF);
+ File f = new File(OneKDC.JAAS_CONF);
+ FileOutputStream fos = new FileOutputStream(f);
+ fos.write((
+ "com.sun.security.jgss.krb5.initiate {\n" +
+ " com.sun.security.auth.module.Krb5LoginModule required;\n};\n" +
+ "com.sun.security.jgss.krb5.accept {\n" +
+ " com.sun.security.auth.module.Krb5LoginModule required\n" +
+ " principal=\"" + OneKDC.SERVER + "\"\n" +
+ " useKeyTab=true\n" +
+ " storeKey=true;\n};\n"
+ ).getBytes());
+ fos.close();
+ Security.setProperty("auth.login.defaultCallbackHandler", "OneKDC$CallbackForClient");
+ c = Context.fromThinAir();
+ s = Context.fromThinAir();
+ b = Context.fromThinAir();
+ c.startAsClient(OneKDC.SERVER, mech);
+ c.x().requestCredDeleg(false);
+ s.startAsServer(mech);
+
+ Context.handshake(c, s);
+ Context p = s.delegated();
+ p.startAsClient(OneKDC.SERVER, mech);
+ b.startAsServer(mech);
+ Context.handshake(p, b);
+
+ String n1 = p.x().getSrcName().toString().split("@")[0];
+ String n2 = b.x().getSrcName().toString().split("@")[0];
+ if (!n1.equals(OneKDC.USER) || !n2.equals(OneKDC.USER)) {
+ throw new Exception("Delegation failed");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/S4U2self.java Wed Nov 07 14:13:01 2012 +0800
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6355584
+ * @summary Introduce constrained Kerberos delegation
+ * @compile -XDignore.symbol.file S4U2self.java
+ * @run main/othervm -Dsun.security.krb5.debug=false S4U2self krb5 0
+ * @run main/othervm/fail -Dsun.security.krb5.debug=false S4U2self krb5 1
+ * @run main/othervm/fail -Dsun.security.krb5.debug=false S4U2self krb5 2
+ * @run main/othervm/fail -Dsun.security.krb5.debug=false S4U2self krb5 3
+ * @run main/othervm/fail -Dsun.security.krb5.debug=false S4U2self krb5 4
+ * @run main/othervm/fail -Dsun.security.krb5.debug=false S4U2self krb5 5
+ * @run main/othervm -Dsun.security.krb5.debug=false S4U2self spnego
+ */
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSUtil;
+
+public class S4U2self {
+
+ public static void main(String[] args) throws Exception {
+ // Test case, different policy settings in KDC:
+ // | ALLOW_S4U2SELF on
+ // | USER USER2 none
+ // ALLOW_S4U2PORXY |-------------------------
+ // USER to BACKEND | 0 1 2
+ // USER2 to BACKEND | 3
+ // USER to SERVER | 4
+ // none | 5
+ //
+ // 0 should succeed, all other fail
+ int test = 0;
+ Oid mech;
+ if (args[0].equals("spnego")) {
+ mech = GSSUtil.GSS_SPNEGO_MECH_OID;
+ } else if (args[0].contains("krb5")) {
+ mech = GSSUtil.GSS_KRB5_MECH_OID;
+ test = Integer.parseInt(args[1]);
+ } else {
+ throw new Exception("Unknown mech");
+ }
+
+ OneKDC kdc = new OneKDC(null);
+ kdc.writeJAASConf();
+
+ switch (test) {
+ case 1:
+ kdc.setOption(KDC.Option.ALLOW_S4U2SELF, Arrays.asList(
+ new String[]{OneKDC.USER2 + "@" + OneKDC.REALM}));
+ break;
+ case 2:
+ // No S4U2self
+ break;
+ default:
+ kdc.setOption(KDC.Option.ALLOW_S4U2SELF, Arrays.asList(
+ new String[]{OneKDC.USER + "@" + OneKDC.REALM}));
+ break;
+ }
+
+ Map<String,List<String>> map = new HashMap<>();
+ switch (test) {
+ case 3:
+ map.put(OneKDC.USER2 + "@" + OneKDC.REALM, Arrays.asList(
+ new String[]{OneKDC.BACKEND + "@" + OneKDC.REALM}));
+ kdc.setOption(KDC.Option.ALLOW_S4U2PROXY, map);
+ break;
+ case 4:
+ map.put(OneKDC.USER + "@" + OneKDC.REALM, Arrays.asList(
+ new String[]{OneKDC.SERVER + "@" + OneKDC.REALM}));
+ kdc.setOption(KDC.Option.ALLOW_S4U2PROXY, map);
+ break;
+ case 5:
+ // No S4U2proxy set
+ break;
+ default:
+ map.put(OneKDC.USER + "@" + OneKDC.REALM, Arrays.asList(
+ new String[]{OneKDC.BACKEND + "@" + OneKDC.REALM}));
+ kdc.setOption(KDC.Option.ALLOW_S4U2PROXY, map);
+ break;
+ }
+
+ Context c, s;
+ c = Context.fromJAAS("client");
+
+ c = c.impersonate(OneKDC.USER2);
+ c.status();
+
+ c.startAsClient(OneKDC.BACKEND, mech);
+
+ s = Context.fromJAAS("backend");
+ s.startAsServer(mech);
+
+ Context.handshake(c, s);
+
+ Context.transmit("i say high --", c, s);
+ Context.transmit(" you say low", s, c);
+
+ c.status();
+ s.status();
+
+ String n1 = c.x().getSrcName().toString().split("@")[0];
+ String n2 = s.x().getSrcName().toString().split("@")[0];
+ if (!n1.equals(OneKDC.USER2) || !n2.equals(OneKDC.USER2)) {
+ throw new Exception("Impersonate failed");
+ }
+
+ s.dispose();
+ c.dispose();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/S4U2selfAsServer.java Wed Nov 07 14:13:01 2012 +0800
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6355584
+ * @summary Introduce constrained Kerberos delegation
+ * @compile -XDignore.symbol.file S4U2selfAsServer.java
+ * @run main/othervm S4U2selfAsServer krb5
+ * @run main/othervm S4U2selfAsServer spnego
+ */
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSUtil;
+
+public class S4U2selfAsServer {
+
+ public static void main(String[] args) throws Exception {
+ Oid mech;
+ if (args[0].equals("spnego")) {
+ mech = GSSUtil.GSS_SPNEGO_MECH_OID;
+ } else if (args[0].contains("krb5")) {
+ mech = GSSUtil.GSS_KRB5_MECH_OID;
+ } else {
+ throw new Exception("Unknown mech");
+ }
+
+ OneKDC kdc = new OneKDC(null);
+ kdc.writeJAASConf();
+ kdc.setOption(KDC.Option.PREAUTH_REQUIRED, false);
+ Map<String,List<String>> map = new HashMap<>();
+ map.put(OneKDC.SERVER + "@" + OneKDC.REALM, Arrays.asList(
+ new String[]{OneKDC.BACKEND + "@" + OneKDC.REALM}));
+ kdc.setOption(KDC.Option.ALLOW_S4U2PROXY, map);
+ kdc.setOption(KDC.Option.ALLOW_S4U2SELF, Arrays.asList(
+ new String[]{OneKDC.SERVER + "@" + OneKDC.REALM}));
+
+ Context s, b;
+ s = Context.fromJAAS("server");
+ b = Context.fromJAAS("backend");
+
+ s.startAsServer(null, mech, false);
+
+ Context p = s.impersonate(OneKDC.USER);
+
+ p.startAsClient(OneKDC.BACKEND, mech);
+ b.startAsServer(mech);
+ Context.handshake(p, b);
+
+ p.startAsClient(OneKDC.BACKEND, mech);
+ b.startAsServer(mech);
+ Context.handshake(p, b);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/S4U2selfAsServerGSS.java Wed Nov 07 14:13:01 2012 +0800
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6355584
+ * @summary Introduce constrained Kerberos delegation
+ * @compile -XDignore.symbol.file S4U2selfAsServerGSS.java
+ * @run main/othervm -Djavax.security.auth.useSubjectCredsOnly=false S4U2selfAsServerGSS krb5
+ * @run main/othervm -Djavax.security.auth.useSubjectCredsOnly=false S4U2selfAsServerGSS spnego
+ */
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSUtil;
+
+public class S4U2selfAsServerGSS {
+
+ public static void main(String[] args) throws Exception {
+ Oid mech;
+ if (args[0].equals("spnego")) {
+ mech = GSSUtil.GSS_SPNEGO_MECH_OID;
+ } else if (args[0].contains("krb5")) {
+ mech = GSSUtil.GSS_KRB5_MECH_OID;
+ } else {
+ throw new Exception("Unknown mech");
+ }
+
+ OneKDC kdc = new OneKDC(null);
+ kdc.writeJAASConf();
+ kdc.setOption(KDC.Option.PREAUTH_REQUIRED, false);
+ Map<String,List<String>> map = new HashMap<>();
+ map.put(OneKDC.SERVER + "@" + OneKDC.REALM, Arrays.asList(
+ new String[]{OneKDC.SERVER + "@" + OneKDC.REALM}));
+ kdc.setOption(KDC.Option.ALLOW_S4U2PROXY, map);
+ kdc.setOption(KDC.Option.ALLOW_S4U2SELF, Arrays.asList(
+ new String[]{OneKDC.SERVER + "@" + OneKDC.REALM}));
+
+ Context s, b;
+ System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
+ System.setProperty("java.security.auth.login.config", OneKDC.JAAS_CONF);
+ File f = new File(OneKDC.JAAS_CONF);
+ FileOutputStream fos = new FileOutputStream(f);
+ fos.write((
+ "com.sun.security.jgss.krb5.accept {\n" +
+ " com.sun.security.auth.module.Krb5LoginModule required\n" +
+ " principal=\"" + OneKDC.SERVER + "\"\n" +
+ " useKeyTab=true\n" +
+ " storeKey=true;\n};\n"
+ ).getBytes());
+ fos.close();
+ Security.setProperty("auth.login.defaultCallbackHandler", "OneKDC$CallbackForClient");
+ s = Context.fromThinAir();
+ b = Context.fromThinAir();
+ s.startAsServer(mech);
+
+ Context p = s.impersonate(OneKDC.USER);
+
+ p.startAsClient(OneKDC.SERVER, mech);
+ b.startAsServer(mech);
+ Context.handshake(p, b);
+
+ String n1 = p.x().getSrcName().toString().split("@")[0];
+ String n2 = b.x().getSrcName().toString().split("@")[0];
+ if (!n1.equals(OneKDC.USER) || !n2.equals(OneKDC.USER)) {
+ throw new Exception("Delegation failed");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/S4U2selfGSS.java Wed Nov 07 14:13:01 2012 +0800
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6355584
+ * @summary Introduce constrained Kerberos delegation
+ * @compile -XDignore.symbol.file S4U2selfGSS.java
+ * @run main/othervm -Dsun.security.krb5.debug=false S4U2selfGSS krb5
+ * @run main/othervm -Dsun.security.krb5.debug=false S4U2selfGSS spnego
+ */
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.ietf.jgss.Oid;
+import sun.security.jgss.GSSUtil;
+
+public class S4U2selfGSS {
+
+ public static void main(String[] args) throws Exception {
+ Oid mech;
+ if (args[0].equals("spnego")) {
+ mech = GSSUtil.GSS_SPNEGO_MECH_OID;
+ } else if (args[0].contains("krb5")) {
+ mech = GSSUtil.GSS_KRB5_MECH_OID;
+ } else {
+ throw new Exception("Unknown mech");
+ }
+
+ OneKDC kdc = new OneKDC(null);
+ kdc.writeJAASConf();
+ kdc.setOption(KDC.Option.ALLOW_S4U2SELF, Arrays.asList(
+ new String[]{OneKDC.USER + "@" + OneKDC.REALM}));
+ Map<String,List<String>> map = new HashMap<>();
+ map.put(OneKDC.USER + "@" + OneKDC.REALM, Arrays.asList(
+ new String[]{OneKDC.SERVER + "@" + OneKDC.REALM}));
+ kdc.setOption(KDC.Option.ALLOW_S4U2PROXY, map);
+
+ Context c, s;
+ System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
+ c = Context.fromThinAir();
+ s = Context.fromThinAir();
+
+ c = c.impersonate(OneKDC.USER2);
+
+ c.startAsClient(OneKDC.SERVER, mech);
+ s.startAsServer(mech);
+
+ Context.handshake(c, s);
+
+ String n1 = c.x().getSrcName().toString().split("@")[0];
+ String n2 = s.x().getSrcName().toString().split("@")[0];
+ if (!n1.equals(OneKDC.USER2) || !n2.equals(OneKDC.USER2)) {
+ throw new Exception("Impersonate failed");
+ }
+
+ s.dispose();
+ c.dispose();
+ }
+}