6355584: Introduce constrained Kerberos delegation
Reviewed-by: valeriep
This commit is contained in:
parent
cae6890e31
commit
5fca8126cd
@ -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;
|
||||
}
|
@ -31,10 +31,19 @@ package sun.security.jgss;
|
||||
* 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 + '}';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,9 @@ package sun.security.jgss;
|
||||
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 class GSSCredentialImpl implements GSSCredential {
|
||||
}
|
||||
}
|
||||
|
||||
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 " +
|
||||
|
@ -35,6 +35,7 @@ public class HttpCaller extends GSSCaller {
|
||||
final private HttpCallerInfo hci;
|
||||
|
||||
public HttpCaller(HttpCallerInfo hci) {
|
||||
super("HTTP_CLIENT");
|
||||
this.hci = hci;
|
||||
}
|
||||
|
||||
|
@ -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 class Krb5AcceptCredential
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ import java.security.PrivilegedActionException;
|
||||
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 @@ class Krb5Context implements GSSContextSpi {
|
||||
* 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 @@ class Krb5Context implements GSSContextSpi {
|
||||
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 @@ class Krb5Context implements GSSContextSpi {
|
||||
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 @@ class Krb5Context implements GSSContextSpi {
|
||||
* 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 @@ class Krb5Context implements GSSContextSpi {
|
||||
* 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 @@ class Krb5Context implements GSSContextSpi {
|
||||
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 @@ class Krb5Context implements GSSContextSpi {
|
||||
"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 @@ class Krb5Context implements GSSContextSpi {
|
||||
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 @@ class Krb5Context implements GSSContextSpi {
|
||||
"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 @@ class Krb5Context implements GSSContextSpi {
|
||||
retVal = new AcceptSecContextToken(this,
|
||||
token.getKrbApReq()).encode();
|
||||
}
|
||||
serviceTicket = token.getKrbApReq().getCreds().getTicket();
|
||||
myCred = null;
|
||||
state = STATE_DONE;
|
||||
} else {
|
||||
@ -802,8 +859,6 @@ class Krb5Context implements GSSContextSpi {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Queries the context for largest data size to accomodate
|
||||
* the specified protection and be <= maxTokSize.
|
||||
|
@ -309,8 +309,7 @@ public class Krb5InitCredential
|
||||
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 @@ public class Krb5InitCredential
|
||||
*/
|
||||
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 @@ public class Krb5InitCredential
|
||||
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 @@ public class Krb5InitCredential
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
@ -206,7 +206,7 @@ public class Krb5Util {
|
||||
* 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 @@ public class Krb5Util {
|
||||
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 @@ public class Krb5Util {
|
||||
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 @@ public class Krb5Util {
|
||||
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 class Krb5Util {
|
||||
};
|
||||
|
||||
public static Credentials ticketToCreds(KerberosTicket kerbTicket)
|
||||
throws KrbException, IOException {
|
||||
throws KrbException, IOException {
|
||||
return new Credentials(
|
||||
kerbTicket.getEncoded(),
|
||||
kerbTicket.getClient().getName(),
|
||||
|
@ -96,4 +96,13 @@ public interface GSSCredentialSpi {
|
||||
* @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;
|
||||
}
|
||||
|
@ -1059,6 +1059,9 @@ public class SpNegoContext implements GSSContextSpi {
|
||||
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) {
|
||||
|
@ -88,4 +88,9 @@ public class SpNegoCredElement implements GSSCredentialSpi {
|
||||
public Oid getMechanism() {
|
||||
return GSSUtil.GSS_SPNEGO_MECH_OID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
return cred.impersonate(name);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import org.ietf.jgss.*;
|
||||
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 @@ public class GSSCredElement implements GSSCredentialSpi {
|
||||
protected void finalize() throws Throwable {
|
||||
dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Not supported yet");
|
||||
}
|
||||
}
|
||||
|
@ -449,6 +449,18 @@ public class Credentials {
|
||||
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 class Credentials {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -160,8 +160,6 @@ public class EncryptedData implements Cloneable {
|
||||
kvno = key.getKeyVersionNumber();
|
||||
}
|
||||
*/
|
||||
|
||||
// currently destructive on cipher
|
||||
public byte[] decrypt(
|
||||
EncryptionKey key, int usage)
|
||||
throws KdcErrException, KrbApErrException, KrbCryptoException {
|
||||
@ -175,7 +173,9 @@ public class EncryptedData implements Cloneable {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -287,8 +287,9 @@ public class KrbApReq {
|
||||
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))
|
||||
|
@ -64,7 +64,12 @@ abstract class KrbKdcRep {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public class KrbTgsRep extends KrbKdcRep {
|
||||
check(false, req, rep);
|
||||
|
||||
this.creds = new Credentials(rep.ticket,
|
||||
req.reqBody.cname,
|
||||
rep.cname,
|
||||
rep.ticket.sname,
|
||||
enc_part.key,
|
||||
enc_part.flags,
|
||||
|
@ -35,6 +35,7 @@ import sun.security.krb5.internal.*;
|
||||
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 @@ public class KrbTgsReq {
|
||||
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 @@ public class KrbTgsReq {
|
||||
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 @@ public class KrbTgsReq {
|
||||
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 @@ public class KrbTgsReq {
|
||||
} 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 @@ public class KrbTgsReq {
|
||||
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 @@ public class KrbTgsReq {
|
||||
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 @@ public class KrbTgsReq {
|
||||
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() {
|
||||
|
@ -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 @@ public class CredentialsUtil {
|
||||
|
||||
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 @@ rs.
|
||||
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 @@ rs.
|
||||
* 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 @@ rs.
|
||||
}
|
||||
} // 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 @@ rs.
|
||||
* 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 @@ rs.
|
||||
* 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 @@ rs.
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -160,9 +160,10 @@ public class EncKDCRepPart {
|
||||
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);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,13 +139,45 @@ public class KDCOptions extends KerberosFlags {
|
||||
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 @@ public class KDCOptions extends KerberosFlags {
|
||||
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 {
|
||||
|
@ -158,6 +158,9 @@ public class Krb5 {
|
||||
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
|
||||
//-------------------------------+-------------
|
||||
|
@ -312,6 +312,9 @@ public class PAData {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Krb5.PA_FOR_USER:
|
||||
sb.append("\t PA-FOR-USER\n");
|
||||
break;
|
||||
default:
|
||||
// Unknown Pre-auth type
|
||||
break;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -54,6 +54,7 @@ public class KeyUsage {
|
||||
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) {
|
||||
|
@ -279,6 +279,9 @@ public class KeyTab implements KeyTabConstants {
|
||||
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)) {
|
||||
|
@ -38,11 +38,13 @@ public class Basic {
|
||||
|
||||
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 @@ public class Basic {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -42,9 +42,10 @@ import org.ietf.jgss.Oid;
|
||||
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 class Context {
|
||||
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 @@ public class Context {
|
||||
* @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 @@ public class Context {
|
||||
} 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 @@ public class Context {
|
||||
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 @@ public class Context {
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 6706974
|
||||
* @compile -XDignore.symbol.file CrossRealm.java
|
||||
* @run main/othervm CrossRealm
|
||||
* @summary Add krb5 test infrastructure
|
||||
*/
|
||||
|
@ -178,6 +178,20 @@ public class KDC {
|
||||
* 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 @@ public class KDC {
|
||||
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 @@ public class KDC {
|
||||
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 @@ public class KDC {
|
||||
}
|
||||
|
||||
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 @@ public class KDC {
|
||||
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 @@ public class KDC {
|
||||
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 @@ public class KDC {
|
||||
);
|
||||
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 @@ public class KDC {
|
||||
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 @@ public class KDC {
|
||||
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 @@ public class KDC {
|
||||
"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 @@ public class KDC {
|
||||
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 @@ public class KDC {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
private static Ticket KDCReqBodyDotFirstAdditionalTicket(KDCReqBody body) {
|
||||
try {
|
||||
return ((Ticket[])getAddlTkt.get(body))[0];
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ public class OkAsDelegate {
|
||||
|
||||
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) {
|
||||
|
79
jdk/test/sun/security/krb5/auto/S4U2proxy.java
Normal file
79
jdk/test/sun/security/krb5/auto/S4U2proxy.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
98
jdk/test/sun/security/krb5/auto/S4U2proxyGSS.java
Normal file
98
jdk/test/sun/security/krb5/auto/S4U2proxyGSS.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
136
jdk/test/sun/security/krb5/auto/S4U2self.java
Normal file
136
jdk/test/sun/security/krb5/auto/S4U2self.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
78
jdk/test/sun/security/krb5/auto/S4U2selfAsServer.java
Normal file
78
jdk/test/sun/security/krb5/auto/S4U2selfAsServer.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
95
jdk/test/sun/security/krb5/auto/S4U2selfAsServerGSS.java
Normal file
95
jdk/test/sun/security/krb5/auto/S4U2selfAsServerGSS.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
82
jdk/test/sun/security/krb5/auto/S4U2selfGSS.java
Normal file
82
jdk/test/sun/security/krb5/auto/S4U2selfGSS.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user