8272162: S4U2Self ticket without forwardable flag
Reviewed-by: valeriep
This commit is contained in:
parent
dd73e3cea2
commit
ab867f6c7c
@ -1365,3 +1365,29 @@ jdk.tls.alpnCharset=ISO_8859_1
|
|||||||
# The default pattern value allows any object factory class specified by the reference
|
# The default pattern value allows any object factory class specified by the reference
|
||||||
# instance to recreate the referenced object.
|
# instance to recreate the referenced object.
|
||||||
#jdk.jndi.object.factoriesFilter=*
|
#jdk.jndi.object.factoriesFilter=*
|
||||||
|
|
||||||
|
#
|
||||||
|
# Policy for non-forwardable service ticket in a S4U2proxy request
|
||||||
|
#
|
||||||
|
# The Service for User to Proxy (S4U2proxy) Kerberos extension enables a middle service
|
||||||
|
# to obtain a service ticket to another service on behalf of a user. It requires that
|
||||||
|
# the user's service ticket to the first service has the forwardable flag set [1].
|
||||||
|
# However, some KDC implementations ignore this requirement and accept service tickets
|
||||||
|
# with the flag unset.
|
||||||
|
#
|
||||||
|
# If this security property is set to "true", then
|
||||||
|
#
|
||||||
|
# 1) The user service ticket, when obtained by the middle service after a S4U2self
|
||||||
|
# impersonation, is not required to have the forwardable flag set; and,
|
||||||
|
#
|
||||||
|
# 2) If a S4U2proxy request receives a KRB_ERROR of the KDC_ERR_BADOPTION error code
|
||||||
|
# and the ticket to the middle service is not forwardable, OpenJDK will try the same
|
||||||
|
# request with another KDC instead of treating it as a fatal failure.
|
||||||
|
#
|
||||||
|
# The default value is "false".
|
||||||
|
#
|
||||||
|
# If a system property of the same name is also specified, it supersedes the
|
||||||
|
# security property value defined here.
|
||||||
|
#
|
||||||
|
# [1] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/bde93b0e-f3c9-4ddf-9f44-e1453be7af5a
|
||||||
|
#jdk.security.krb5.s4u2proxy.acceptNonForwardableServiceTicket=false
|
||||||
|
@ -45,7 +45,6 @@ import javax.security.auth.kerberos.ServicePermission;
|
|||||||
import javax.security.auth.kerberos.KerberosCredMessage;
|
import javax.security.auth.kerberos.KerberosCredMessage;
|
||||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||||
import javax.security.auth.kerberos.KerberosTicket;
|
import javax.security.auth.kerberos.KerberosTicket;
|
||||||
import sun.security.krb5.internal.Ticket;
|
|
||||||
import sun.security.krb5.internal.AuthorizationData;
|
import sun.security.krb5.internal.AuthorizationData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,9 +119,12 @@ class Krb5Context implements GSSContextSpi {
|
|||||||
// XXX See if the required info from these can be extracted and
|
// XXX See if the required info from these can be extracted and
|
||||||
// stored elsewhere
|
// stored elsewhere
|
||||||
private Credentials tgt;
|
private Credentials tgt;
|
||||||
|
|
||||||
|
// On the Initiator side, contains the final TGS to a service on both
|
||||||
|
// delegation and no-delegation scenarios.
|
||||||
|
// On the Acceptor side, contains a user TGS usable for delegation.
|
||||||
private Credentials serviceCreds;
|
private Credentials serviceCreds;
|
||||||
private KrbApReq apReq;
|
private KrbApReq apReq;
|
||||||
Ticket serviceTicket;
|
|
||||||
private final GSSCaller caller;
|
private final GSSCaller caller;
|
||||||
private static final boolean DEBUG = Krb5Util.DEBUG;
|
private static final boolean DEBUG = Krb5Util.DEBUG;
|
||||||
|
|
||||||
@ -548,7 +550,7 @@ class Krb5Context implements GSSContextSpi {
|
|||||||
delegatedCred = new Krb5ProxyCredential(
|
delegatedCred = new Krb5ProxyCredential(
|
||||||
Krb5InitCredential.getInstance(
|
Krb5InitCredential.getInstance(
|
||||||
GSSCaller.CALLER_ACCEPT, myName, lifetime),
|
GSSCaller.CALLER_ACCEPT, myName, lifetime),
|
||||||
peerName, serviceTicket);
|
peerName, serviceCreds);
|
||||||
} catch (GSSException gsse) {
|
} catch (GSSException gsse) {
|
||||||
// OK, delegatedCred is null then
|
// OK, delegatedCred is null then
|
||||||
}
|
}
|
||||||
@ -623,13 +625,13 @@ class Krb5Context implements GSSContextSpi {
|
|||||||
"No TGT available");
|
"No TGT available");
|
||||||
}
|
}
|
||||||
myName = (Krb5NameElement) myCred.getName();
|
myName = (Krb5NameElement) myCred.getName();
|
||||||
final Krb5ProxyCredential second;
|
final Krb5ProxyCredential proxyCreds;
|
||||||
if (myCred instanceof Krb5InitCredential) {
|
if (myCred instanceof Krb5InitCredential) {
|
||||||
second = null;
|
proxyCreds = null;
|
||||||
tgt = ((Krb5InitCredential) myCred).getKrb5Credentials();
|
tgt = ((Krb5InitCredential) myCred).getKrb5Credentials();
|
||||||
} else {
|
} else {
|
||||||
second = (Krb5ProxyCredential) myCred;
|
proxyCreds = (Krb5ProxyCredential) myCred;
|
||||||
tgt = second.self.getKrb5Credentials();
|
tgt = proxyCreds.self.getKrb5Credentials();
|
||||||
}
|
}
|
||||||
|
|
||||||
checkPermission(peerName.getKrb5PrincipalName().getName(),
|
checkPermission(peerName.getKrb5PrincipalName().getName(),
|
||||||
@ -657,9 +659,9 @@ class Krb5Context implements GSSContextSpi {
|
|||||||
GSSCaller.CALLER_UNKNOWN,
|
GSSCaller.CALLER_UNKNOWN,
|
||||||
// since it's useSubjectCredsOnly here,
|
// since it's useSubjectCredsOnly here,
|
||||||
// don't worry about the null
|
// don't worry about the null
|
||||||
second == null ?
|
proxyCreds == null ?
|
||||||
myName.getKrb5PrincipalName().getName():
|
myName.getKrb5PrincipalName().getName():
|
||||||
second.getName().getKrb5PrincipalName().getName(),
|
proxyCreds.getName().getKrb5PrincipalName().getName(),
|
||||||
peerName.getKrb5PrincipalName().getName());
|
peerName.getKrb5PrincipalName().getName());
|
||||||
}});
|
}});
|
||||||
kerbTicket = tmp;
|
kerbTicket = tmp;
|
||||||
@ -690,15 +692,15 @@ class Krb5Context implements GSSContextSpi {
|
|||||||
"the subject");
|
"the subject");
|
||||||
}
|
}
|
||||||
// Get Service ticket using the Kerberos protocols
|
// Get Service ticket using the Kerberos protocols
|
||||||
if (second == null) {
|
if (proxyCreds == null) {
|
||||||
serviceCreds = Credentials.acquireServiceCreds(
|
serviceCreds = Credentials.acquireServiceCreds(
|
||||||
peerName.getKrb5PrincipalName().getName(),
|
peerName.getKrb5PrincipalName().getName(),
|
||||||
tgt);
|
tgt);
|
||||||
} else {
|
} else {
|
||||||
serviceCreds = Credentials.acquireS4U2proxyCreds(
|
serviceCreds = Credentials.acquireS4U2proxyCreds(
|
||||||
peerName.getKrb5PrincipalName().getName(),
|
peerName.getKrb5PrincipalName().getName(),
|
||||||
second.tkt,
|
proxyCreds.userCreds,
|
||||||
second.getName().getKrb5PrincipalName(),
|
proxyCreds.getName().getKrb5PrincipalName(),
|
||||||
tgt);
|
tgt);
|
||||||
}
|
}
|
||||||
if (GSSUtil.useSubjectCredsOnly(caller)) {
|
if (GSSUtil.useSubjectCredsOnly(caller)) {
|
||||||
@ -844,7 +846,7 @@ class Krb5Context implements GSSContextSpi {
|
|||||||
retVal = new AcceptSecContextToken(this,
|
retVal = new AcceptSecContextToken(this,
|
||||||
token.getKrbApReq()).encode();
|
token.getKrbApReq()).encode();
|
||||||
}
|
}
|
||||||
serviceTicket = token.getKrbApReq().getCreds().getTicket();
|
serviceCreds = token.getKrbApReq().getCreds();
|
||||||
myCred = null;
|
myCred = null;
|
||||||
state = STATE_DONE;
|
state = STATE_DONE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -392,7 +392,7 @@ public class Krb5InitCredential
|
|||||||
Krb5NameElement kname = (Krb5NameElement)name;
|
Krb5NameElement kname = (Krb5NameElement)name;
|
||||||
Credentials newCred = Credentials.acquireS4U2selfCreds(
|
Credentials newCred = Credentials.acquireS4U2selfCreds(
|
||||||
kname.getKrb5PrincipalName(), krb5Credentials);
|
kname.getKrb5PrincipalName(), krb5Credentials);
|
||||||
return new Krb5ProxyCredential(this, kname, newCred.getTicket());
|
return new Krb5ProxyCredential(this, kname, newCred);
|
||||||
} catch (IOException | KrbException ke) {
|
} catch (IOException | KrbException ke) {
|
||||||
GSSException ge =
|
GSSException ge =
|
||||||
new GSSException(GSSException.FAILURE, -1,
|
new GSSException(GSSException.FAILURE, -1,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -33,7 +33,6 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import sun.security.krb5.Credentials;
|
import sun.security.krb5.Credentials;
|
||||||
import sun.security.krb5.KrbException;
|
import sun.security.krb5.KrbException;
|
||||||
import sun.security.krb5.internal.Ticket;
|
|
||||||
|
|
||||||
import javax.security.auth.kerberos.KerberosTicket;
|
import javax.security.auth.kerberos.KerberosTicket;
|
||||||
|
|
||||||
@ -50,23 +49,23 @@ public class Krb5ProxyCredential
|
|||||||
implements Krb5CredElement {
|
implements Krb5CredElement {
|
||||||
|
|
||||||
public final Krb5InitCredential self; // the middle server
|
public final Krb5InitCredential self; // the middle server
|
||||||
private final Krb5NameElement client; // the client
|
private final Krb5NameElement user; // the user
|
||||||
|
|
||||||
// The ticket with cname=client and sname=self. This can be a normal
|
// The creds with cname=user and sname=self. The ticket inside can
|
||||||
// service ticket or an S4U2self ticket.
|
// be either a normal service ticket or an S4U2self ticket.
|
||||||
public final Ticket tkt;
|
public final Credentials userCreds;
|
||||||
|
|
||||||
Krb5ProxyCredential(Krb5InitCredential self, Krb5NameElement client,
|
Krb5ProxyCredential(Krb5InitCredential self, Krb5NameElement user,
|
||||||
Ticket tkt) {
|
Credentials userCreds) {
|
||||||
this.self = self;
|
this.self = self;
|
||||||
this.tkt = tkt;
|
this.userCreds = userCreds;
|
||||||
this.client = client;
|
this.user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The client name behind the proxy
|
// The user name behind the proxy
|
||||||
@Override
|
@Override
|
||||||
public final Krb5NameElement getName() throws GSSException {
|
public final Krb5NameElement getName() throws GSSException {
|
||||||
return client;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -130,7 +129,7 @@ public class Krb5ProxyCredential
|
|||||||
Credentials proxyCreds = Krb5Util.ticketToCreds(proxy);
|
Credentials proxyCreds = Krb5Util.ticketToCreds(proxy);
|
||||||
return new Krb5ProxyCredential(initiator,
|
return new Krb5ProxyCredential(initiator,
|
||||||
Krb5NameElement.getInstance(proxyCreds.getClient()),
|
Krb5NameElement.getInstance(proxyCreds.getClient()),
|
||||||
proxyCreds.getTicket());
|
proxyCreds);
|
||||||
} else {
|
} else {
|
||||||
return initiator;
|
return initiator;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ import sun.security.action.GetPropertyAction;
|
|||||||
import sun.security.krb5.internal.*;
|
import sun.security.krb5.internal.*;
|
||||||
import sun.security.krb5.internal.ccache.CredentialsCache;
|
import sun.security.krb5.internal.ccache.CredentialsCache;
|
||||||
import sun.security.krb5.internal.crypto.EType;
|
import sun.security.krb5.internal.crypto.EType;
|
||||||
|
import sun.security.util.SecurityProperties;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -64,6 +66,10 @@ public class Credentials {
|
|||||||
static boolean alreadyLoaded = false;
|
static boolean alreadyLoaded = false;
|
||||||
private static boolean alreadyTried = false;
|
private static boolean alreadyTried = false;
|
||||||
|
|
||||||
|
public static final boolean S4U2PROXY_ACCEPT_NON_FORWARDABLE
|
||||||
|
= "true".equalsIgnoreCase(SecurityProperties.privilegedGetOverridable(
|
||||||
|
"jdk.security.krb5.s4u2proxy.acceptNonForwardableServiceTicket"));
|
||||||
|
|
||||||
private Credentials proxy = null;
|
private Credentials proxy = null;
|
||||||
|
|
||||||
public Credentials getProxy() {
|
public Credentials getProxy() {
|
||||||
@ -97,7 +103,7 @@ public class Credentials {
|
|||||||
this.authzData = authzData;
|
this.authzData = authzData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning: called by NativeCreds.c and nativeccache.c
|
// Warning: also called by NativeCreds.c and nativeccache.c
|
||||||
public Credentials(Ticket new_ticket,
|
public Credentials(Ticket new_ticket,
|
||||||
PrincipalName new_client,
|
PrincipalName new_client,
|
||||||
PrincipalName new_client_alias,
|
PrincipalName new_client_alias,
|
||||||
@ -478,7 +484,7 @@ public class Credentials {
|
|||||||
*
|
*
|
||||||
* @param service the name of service principal using format
|
* @param service the name of service principal using format
|
||||||
* components@realm
|
* components@realm
|
||||||
* @param ccreds client's initial credential.
|
* @param initCreds client's initial credential.
|
||||||
* @exception IOException if an error occurs in reading the credentials
|
* @exception IOException if an error occurs in reading the credentials
|
||||||
* cache
|
* cache
|
||||||
* @exception KrbException if an error occurs specific to Kerberos
|
* @exception KrbException if an error occurs specific to Kerberos
|
||||||
@ -486,21 +492,21 @@ public class Credentials {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public static Credentials acquireServiceCreds(String service,
|
public static Credentials acquireServiceCreds(String service,
|
||||||
Credentials ccreds)
|
Credentials initCreds)
|
||||||
throws KrbException, IOException {
|
throws KrbException, IOException {
|
||||||
return CredentialsUtil.acquireServiceCreds(service, ccreds);
|
return CredentialsUtil.acquireServiceCreds(service, initCreds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Credentials acquireS4U2selfCreds(PrincipalName user,
|
public static Credentials acquireS4U2selfCreds(PrincipalName user,
|
||||||
Credentials ccreds) throws KrbException, IOException {
|
Credentials middleTGT) throws KrbException, IOException {
|
||||||
return CredentialsUtil.acquireS4U2selfCreds(user, ccreds);
|
return CredentialsUtil.acquireS4U2selfCreds(user, middleTGT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Credentials acquireS4U2proxyCreds(String service,
|
public static Credentials acquireS4U2proxyCreds(String service,
|
||||||
Ticket second, PrincipalName client, Credentials ccreds)
|
Credentials userCreds, PrincipalName client, Credentials middleTGT)
|
||||||
throws KrbException, IOException {
|
throws KrbException, IOException {
|
||||||
return CredentialsUtil.acquireS4U2proxyCreds(
|
return CredentialsUtil.acquireS4U2proxyCreds(
|
||||||
service, second, client, ccreds);
|
service, userCreds, client, middleTGT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -188,21 +188,22 @@ public final class KdcComm {
|
|||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] send(byte[] obuf)
|
public byte[] send(KrbKdcReq req)
|
||||||
throws IOException, KrbException {
|
throws IOException, KrbException {
|
||||||
int udpPrefLimit = getRealmSpecificValue(
|
int udpPrefLimit = getRealmSpecificValue(
|
||||||
realm, "udp_preference_limit", defaultUdpPrefLimit);
|
realm, "udp_preference_limit", defaultUdpPrefLimit);
|
||||||
|
|
||||||
|
byte[] obuf = req.encoding();
|
||||||
boolean useTCP = (udpPrefLimit > 0 &&
|
boolean useTCP = (udpPrefLimit > 0 &&
|
||||||
(obuf != null && obuf.length > udpPrefLimit));
|
(obuf != null && obuf.length > udpPrefLimit));
|
||||||
|
|
||||||
return send(obuf, useTCP);
|
return send(req, useTCP);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] send(byte[] obuf, boolean useTCP)
|
private byte[] send(KrbKdcReq req, boolean useTCP)
|
||||||
throws IOException, KrbException {
|
throws IOException, KrbException {
|
||||||
|
|
||||||
if (obuf == null)
|
if (req == null)
|
||||||
return null;
|
return null;
|
||||||
Config cfg = Config.getInstance();
|
Config cfg = Config.getInstance();
|
||||||
|
|
||||||
@ -225,12 +226,12 @@ public final class KdcComm {
|
|||||||
}
|
}
|
||||||
byte[] ibuf = null;
|
byte[] ibuf = null;
|
||||||
try {
|
try {
|
||||||
ibuf = sendIfPossible(obuf, tempKdc.next(), useTCP);
|
ibuf = sendIfPossible(req, tempKdc.next(), useTCP);
|
||||||
} catch(Exception first) {
|
} catch(Exception first) {
|
||||||
boolean ok = false;
|
boolean ok = false;
|
||||||
while(tempKdc.hasNext()) {
|
while(tempKdc.hasNext()) {
|
||||||
try {
|
try {
|
||||||
ibuf = sendIfPossible(obuf, tempKdc.next(), useTCP);
|
ibuf = sendIfPossible(req, tempKdc.next(), useTCP);
|
||||||
ok = true;
|
ok = true;
|
||||||
break;
|
break;
|
||||||
} catch(Exception ignore) {}
|
} catch(Exception ignore) {}
|
||||||
@ -243,13 +244,13 @@ public final class KdcComm {
|
|||||||
return ibuf;
|
return ibuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the AS Request to the specified KDC
|
// send the KDC Request to the specified KDC
|
||||||
// failover to using TCP if useTCP is not set and response is too big
|
// failover to using TCP if useTCP is not set and response is too big
|
||||||
private byte[] sendIfPossible(byte[] obuf, String tempKdc, boolean useTCP)
|
private byte[] sendIfPossible(KrbKdcReq req, String tempKdc, boolean useTCP)
|
||||||
throws IOException, KrbException {
|
throws IOException, KrbException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
byte[] ibuf = send(obuf, tempKdc, useTCP);
|
byte[] ibuf = send(req, tempKdc, useTCP);
|
||||||
KRBError ke = null;
|
KRBError ke = null;
|
||||||
try {
|
try {
|
||||||
ke = new KRBError(ibuf);
|
ke = new KRBError(ibuf);
|
||||||
@ -259,10 +260,17 @@ public final class KdcComm {
|
|||||||
if (ke != null) {
|
if (ke != null) {
|
||||||
if (ke.getErrorCode() ==
|
if (ke.getErrorCode() ==
|
||||||
Krb5.KRB_ERR_RESPONSE_TOO_BIG) {
|
Krb5.KRB_ERR_RESPONSE_TOO_BIG) {
|
||||||
ibuf = send(obuf, tempKdc, true);
|
ibuf = send(req, tempKdc, true);
|
||||||
} else if (ke.getErrorCode() ==
|
} else if (ke.getErrorCode() ==
|
||||||
Krb5.KDC_ERR_SVC_UNAVAILABLE) {
|
Krb5.KDC_ERR_SVC_UNAVAILABLE) {
|
||||||
throw new KrbException("A service is not available");
|
throw new KrbException("A service is not available");
|
||||||
|
} else if (ke.getErrorCode() == Krb5.KDC_ERR_BADOPTION
|
||||||
|
&& Credentials.S4U2PROXY_ACCEPT_NON_FORWARDABLE
|
||||||
|
&& req instanceof KrbTgsReq tgsReq) {
|
||||||
|
Credentials extra = tgsReq.getAdditionalCreds();
|
||||||
|
if (extra != null && !extra.isForwardable()) {
|
||||||
|
throw new KrbException("S4U2Proxy with non-forwardable ticket");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KdcAccessibility.removeBad(tempKdc);
|
KdcAccessibility.removeBad(tempKdc);
|
||||||
@ -278,12 +286,12 @@ public final class KdcComm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the AS Request to the specified KDC
|
// send the KDC Request to the specified KDC
|
||||||
|
|
||||||
private byte[] send(byte[] obuf, String tempKdc, boolean useTCP)
|
private byte[] send(KrbKdcReq req, String tempKdc, boolean useTCP)
|
||||||
throws IOException, KrbException {
|
throws IOException, KrbException {
|
||||||
|
|
||||||
if (obuf == null)
|
if (req == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
int port = Krb5.KDC_INET_DEFAULT_PORT;
|
int port = Krb5.KDC_INET_DEFAULT_PORT;
|
||||||
@ -336,6 +344,7 @@ public final class KdcComm {
|
|||||||
port = tempPort;
|
port = tempPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] obuf = req.encoding();
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.println(">>> KrbKdcReq send: kdc=" + kdc
|
System.out.println(">>> KrbKdcReq send: kdc=" + kdc
|
||||||
+ (useTCP ? " TCP:":" UDP:")
|
+ (useTCP ? " TCP:":" UDP:")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -42,7 +42,7 @@ import java.util.Arrays;
|
|||||||
* This class encapsulates the KRB-AS-REQ message that the client
|
* This class encapsulates the KRB-AS-REQ message that the client
|
||||||
* sends to the KDC.
|
* sends to the KDC.
|
||||||
*/
|
*/
|
||||||
public class KrbAsReq {
|
public class KrbAsReq extends KrbKdcReq {
|
||||||
private ASReq asReqMessg;
|
private ASReq asReqMessg;
|
||||||
|
|
||||||
private boolean DEBUG = Krb5.DEBUG;
|
private boolean DEBUG = Krb5.DEBUG;
|
||||||
@ -165,10 +165,7 @@ public class KrbAsReq {
|
|||||||
asReqMessg = new ASReq(
|
asReqMessg = new ASReq(
|
||||||
paData,
|
paData,
|
||||||
kdc_req_body);
|
kdc_req_body);
|
||||||
}
|
obuf = asReqMessg.asn1Encode();
|
||||||
|
|
||||||
byte[] encoding() throws IOException, Asn1Exception {
|
|
||||||
return asReqMessg.asn1Encode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by KrbAsRep to validate AS-REP
|
// Used by KrbAsRep to validate AS-REP
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -342,7 +342,7 @@ public final class KrbAsReqBuilder {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
req = build(pakey, referralsState);
|
req = build(pakey, referralsState);
|
||||||
rep = new KrbAsRep(comm.send(req.encoding()));
|
rep = new KrbAsRep(comm.send(req));
|
||||||
return this;
|
return this;
|
||||||
} catch (KrbException ke) {
|
} catch (KrbException ke) {
|
||||||
if (!preAuthFailedOnce && (
|
if (!preAuthFailedOnce && (
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent class for KrbAsReq and KrbTgsReq.
|
||||||
|
*/
|
||||||
|
abstract class KrbKdcReq {
|
||||||
|
|
||||||
|
protected byte[] obuf;
|
||||||
|
|
||||||
|
public byte[] encoding() {
|
||||||
|
return obuf;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -43,7 +43,7 @@ import java.io.IOException;
|
|||||||
public class KrbTgsRep extends KrbKdcRep {
|
public class KrbTgsRep extends KrbKdcRep {
|
||||||
private TGSRep rep;
|
private TGSRep rep;
|
||||||
private Credentials creds;
|
private Credentials creds;
|
||||||
private Ticket secondTicket;
|
private Credentials additionalCreds;
|
||||||
|
|
||||||
KrbTgsRep(byte[] ibuf, KrbTgsReq tgsReq)
|
KrbTgsRep(byte[] ibuf, KrbTgsReq tgsReq)
|
||||||
throws KrbException, IOException {
|
throws KrbException, IOException {
|
||||||
@ -115,7 +115,7 @@ public class KrbTgsRep extends KrbKdcRep {
|
|||||||
enc_part.caddr
|
enc_part.caddr
|
||||||
);
|
);
|
||||||
this.rep = rep;
|
this.rep = rep;
|
||||||
this.secondTicket = tgsReq.getSecondTicket();
|
this.additionalCreds = tgsReq.getAdditionalCreds();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,7 +126,8 @@ public class KrbTgsRep extends KrbKdcRep {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sun.security.krb5.internal.ccache.Credentials setCredentials() {
|
sun.security.krb5.internal.ccache.Credentials setCredentials() {
|
||||||
return new sun.security.krb5.internal.ccache.Credentials(rep, secondTicket);
|
return new sun.security.krb5.internal.ccache.Credentials(
|
||||||
|
rep, additionalCreds == null ? null : additionalCreds.ticket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isReferralSname(PrincipalName sname) {
|
private static boolean isReferralSname(PrincipalName sname) {
|
||||||
|
@ -42,7 +42,7 @@ import java.util.Arrays;
|
|||||||
* This class encapsulates a Kerberos TGS-REQ that is sent from the
|
* This class encapsulates a Kerberos TGS-REQ that is sent from the
|
||||||
* client to the KDC.
|
* client to the KDC.
|
||||||
*/
|
*/
|
||||||
public class KrbTgsReq {
|
public class KrbTgsReq extends KrbKdcReq {
|
||||||
|
|
||||||
private PrincipalName princName;
|
private PrincipalName princName;
|
||||||
private PrincipalName clientAlias;
|
private PrincipalName clientAlias;
|
||||||
@ -50,18 +50,15 @@ public class KrbTgsReq {
|
|||||||
private PrincipalName serverAlias;
|
private PrincipalName serverAlias;
|
||||||
private TGSReq tgsReqMessg;
|
private TGSReq tgsReqMessg;
|
||||||
private KerberosTime ctime;
|
private KerberosTime ctime;
|
||||||
private Ticket secondTicket = null;
|
private Credentials additionalCreds = null;
|
||||||
private boolean useSubkey = false;
|
private boolean useSubkey = false;
|
||||||
EncryptionKey tgsReqKey;
|
EncryptionKey tgsReqKey;
|
||||||
|
|
||||||
private byte[] obuf;
|
|
||||||
private byte[] ibuf;
|
|
||||||
|
|
||||||
// Used in CredentialsUtil
|
// Used in CredentialsUtil
|
||||||
public KrbTgsReq(KDCOptions options, Credentials asCreds,
|
public KrbTgsReq(KDCOptions options, Credentials asCreds,
|
||||||
PrincipalName cname, PrincipalName clientAlias,
|
PrincipalName cname, PrincipalName clientAlias,
|
||||||
PrincipalName sname, PrincipalName serverAlias,
|
PrincipalName sname, PrincipalName serverAlias,
|
||||||
Ticket[] additionalTickets, PAData[] extraPAs)
|
Credentials additionalCreds, PAData[] extraPAs)
|
||||||
throws KrbException, IOException {
|
throws KrbException, IOException {
|
||||||
this(options,
|
this(options,
|
||||||
asCreds,
|
asCreds,
|
||||||
@ -75,7 +72,7 @@ public class KrbTgsReq {
|
|||||||
null, // int[] eTypes
|
null, // int[] eTypes
|
||||||
null, // HostAddresses addresses
|
null, // HostAddresses addresses
|
||||||
null, // AuthorizationData authorizationData
|
null, // AuthorizationData authorizationData
|
||||||
additionalTickets,
|
additionalCreds,
|
||||||
null, // EncryptionKey subKey
|
null, // EncryptionKey subKey
|
||||||
extraPAs);
|
extraPAs);
|
||||||
}
|
}
|
||||||
@ -92,11 +89,11 @@ public class KrbTgsReq {
|
|||||||
int[] eTypes,
|
int[] eTypes,
|
||||||
HostAddresses addresses,
|
HostAddresses addresses,
|
||||||
AuthorizationData authorizationData,
|
AuthorizationData authorizationData,
|
||||||
Ticket[] additionalTickets,
|
Credentials additionalCreds,
|
||||||
EncryptionKey subKey) throws KrbException, IOException {
|
EncryptionKey subKey) throws KrbException, IOException {
|
||||||
this(options, asCreds, asCreds.getClient(), asCreds.getClientAlias(),
|
this(options, asCreds, asCreds.getClient(), asCreds.getClientAlias(),
|
||||||
sname, serverAlias, from, till, rtime, eTypes,
|
sname, serverAlias, from, till, rtime, eTypes,
|
||||||
addresses, authorizationData, additionalTickets, subKey, null);
|
addresses, authorizationData, additionalCreds, subKey, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private KrbTgsReq(
|
private KrbTgsReq(
|
||||||
@ -112,7 +109,7 @@ public class KrbTgsReq {
|
|||||||
int[] eTypes,
|
int[] eTypes,
|
||||||
HostAddresses addresses,
|
HostAddresses addresses,
|
||||||
AuthorizationData authorizationData,
|
AuthorizationData authorizationData,
|
||||||
Ticket[] additionalTickets,
|
Credentials additionalCreds,
|
||||||
EncryptionKey subKey,
|
EncryptionKey subKey,
|
||||||
PAData[] extraPAs) throws KrbException, IOException {
|
PAData[] extraPAs) throws KrbException, IOException {
|
||||||
|
|
||||||
@ -163,15 +160,15 @@ public class KrbTgsReq {
|
|||||||
if (rtime != null) rtime = null;
|
if (rtime != null) rtime = null;
|
||||||
}
|
}
|
||||||
if (options.get(KDCOptions.ENC_TKT_IN_SKEY) || options.get(KDCOptions.CNAME_IN_ADDL_TKT)) {
|
if (options.get(KDCOptions.ENC_TKT_IN_SKEY) || options.get(KDCOptions.CNAME_IN_ADDL_TKT)) {
|
||||||
if (additionalTickets == null)
|
if (additionalCreds == null)
|
||||||
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
|
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
|
||||||
// in TGS_REQ there could be more than one additional
|
// in TGS_REQ there could be more than one additional
|
||||||
// tickets, but in file-based credential cache,
|
// tickets, but in file-based credential cache,
|
||||||
// there is only one additional ticket field.
|
// there is only one additional ticket field.
|
||||||
secondTicket = additionalTickets[0];
|
this.additionalCreds = additionalCreds;
|
||||||
} else {
|
} else {
|
||||||
if (additionalTickets != null)
|
if (additionalCreds != null)
|
||||||
additionalTickets = null;
|
additionalCreds = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
tgsReqMessg = createRequest(
|
tgsReqMessg = createRequest(
|
||||||
@ -187,7 +184,7 @@ public class KrbTgsReq {
|
|||||||
eTypes,
|
eTypes,
|
||||||
addresses,
|
addresses,
|
||||||
authorizationData,
|
authorizationData,
|
||||||
additionalTickets,
|
additionalCreds,
|
||||||
subKey,
|
subKey,
|
||||||
extraPAs);
|
extraPAs);
|
||||||
obuf = tgsReqMessg.asn1Encode();
|
obuf = tgsReqMessg.asn1Encode();
|
||||||
@ -206,34 +203,16 @@ public class KrbTgsReq {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a TGS request to the realm of the target.
|
|
||||||
* @throws KrbException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public void send() throws IOException, KrbException {
|
|
||||||
String realmStr = null;
|
|
||||||
if (servName != null)
|
|
||||||
realmStr = servName.getRealmString();
|
|
||||||
KdcComm comm = new KdcComm(realmStr);
|
|
||||||
ibuf = comm.send(obuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
public KrbTgsRep getReply()
|
|
||||||
throws KrbException, IOException {
|
|
||||||
return new KrbTgsRep(ibuf, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the request, waits for a reply, and returns the Credentials.
|
* Sends the request, waits for a reply, and returns the Credentials.
|
||||||
* Used in Credentials, KrbCred, and internal/CredentialsUtil.
|
* Used in Credentials, KrbCred, and internal/CredentialsUtil.
|
||||||
*/
|
*/
|
||||||
public Credentials sendAndGetCreds() throws IOException, KrbException {
|
public Credentials sendAndGetCreds() throws IOException, KrbException {
|
||||||
KrbTgsRep tgs_rep = null;
|
String realmStr = servName != null
|
||||||
String kdc = null;
|
? servName.getRealmString()
|
||||||
send();
|
: null;
|
||||||
tgs_rep = getReply();
|
KdcComm comm = new KdcComm(realmStr);
|
||||||
return tgs_rep.getCreds();
|
return new KrbTgsRep(comm.send(this), this).getCreds();
|
||||||
}
|
}
|
||||||
|
|
||||||
KerberosTime getCtime() {
|
KerberosTime getCtime() {
|
||||||
@ -253,7 +232,7 @@ public class KrbTgsReq {
|
|||||||
int[] eTypes,
|
int[] eTypes,
|
||||||
HostAddresses addresses,
|
HostAddresses addresses,
|
||||||
AuthorizationData authorizationData,
|
AuthorizationData authorizationData,
|
||||||
Ticket[] additionalTickets,
|
Credentials additionalCreds,
|
||||||
EncryptionKey subKey,
|
EncryptionKey subKey,
|
||||||
PAData[] extraPAs)
|
PAData[] extraPAs)
|
||||||
throws IOException, KrbException, UnknownHostException {
|
throws IOException, KrbException, UnknownHostException {
|
||||||
@ -302,6 +281,8 @@ public class KrbTgsReq {
|
|||||||
KeyUsage.KU_TGS_REQ_AUTH_DATA_SESSKEY);
|
KeyUsage.KU_TGS_REQ_AUTH_DATA_SESSKEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ticket[] additionalTickets = additionalCreds == null ? null
|
||||||
|
: new Ticket[] { additionalCreds.getTicket() };
|
||||||
KDCReqBody reqBody = new KDCReqBody(
|
KDCReqBody reqBody = new KDCReqBody(
|
||||||
kdc_options,
|
kdc_options,
|
||||||
cname,
|
cname,
|
||||||
@ -347,8 +328,8 @@ public class KrbTgsReq {
|
|||||||
return tgsReqMessg;
|
return tgsReqMessg;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ticket getSecondTicket() {
|
Credentials getAdditionalCreds() {
|
||||||
return secondTicket;
|
return additionalCreds;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrincipalName getClientAlias() {
|
PrincipalName getClientAlias() {
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
package sun.security.krb5.internal;
|
package sun.security.krb5.internal;
|
||||||
|
|
||||||
import sun.security.krb5.*;
|
import sun.security.krb5.*;
|
||||||
import sun.security.util.DerValue;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -55,17 +54,14 @@ public class CredentialsUtil {
|
|||||||
* Used by a middle server to acquire credentials on behalf of a
|
* Used by a middle server to acquire credentials on behalf of a
|
||||||
* user to itself using the S4U2self extension.
|
* user to itself using the S4U2self extension.
|
||||||
* @param user the user to impersonate
|
* @param user the user to impersonate
|
||||||
* @param ccreds the TGT of the middle service
|
* @param middleTGT the TGT of the middle service
|
||||||
* @return the new creds (cname=user, sname=middle)
|
* @return the new creds (cname=user, sname=middle)
|
||||||
*/
|
*/
|
||||||
public static Credentials acquireS4U2selfCreds(PrincipalName user,
|
public static Credentials acquireS4U2selfCreds(PrincipalName user,
|
||||||
Credentials ccreds) throws KrbException, IOException {
|
Credentials middleTGT) throws KrbException, IOException {
|
||||||
if (!ccreds.isForwardable()) {
|
PrincipalName sname = middleTGT.getClient();
|
||||||
throw new KrbException("S4U2self needs a FORWARDABLE ticket");
|
|
||||||
}
|
|
||||||
PrincipalName sname = ccreds.getClient();
|
|
||||||
String uRealm = user.getRealmString();
|
String uRealm = user.getRealmString();
|
||||||
String localRealm = ccreds.getClient().getRealmString();
|
String localRealm = sname.getRealmString();
|
||||||
if (!uRealm.equals(localRealm)) {
|
if (!uRealm.equals(localRealm)) {
|
||||||
// Referrals will be required because the middle service
|
// Referrals will be required because the middle service
|
||||||
// and the user impersonated are on different realms.
|
// and the user impersonated are on different realms.
|
||||||
@ -73,25 +69,25 @@ public class CredentialsUtil {
|
|||||||
throw new KrbException("Cross-realm S4U2Self request not" +
|
throw new KrbException("Cross-realm S4U2Self request not" +
|
||||||
" possible when referrals are disabled.");
|
" possible when referrals are disabled.");
|
||||||
}
|
}
|
||||||
if (ccreds.getClientAlias() != null) {
|
if (middleTGT.getClientAlias() != null) {
|
||||||
// If the name was canonicalized, the user pick
|
// If the name was canonicalized, the user pick
|
||||||
// has preference. This gives the possibility of
|
// has preference. This gives the possibility of
|
||||||
// using FQDNs that KDCs may use to return referrals.
|
// using FQDNs that KDCs may use to return referrals.
|
||||||
// I.e.: a SVC/host.realm-2.com@REALM-1.COM name
|
// I.e.: a SVC/host.realm-2.com@REALM-1.COM name
|
||||||
// may be used by REALM-1.COM KDC to return a
|
// may be used by REALM-1.COM KDC to return a
|
||||||
// referral to REALM-2.COM.
|
// referral to REALM-2.COM.
|
||||||
sname = ccreds.getClientAlias();
|
sname = middleTGT.getClientAlias();
|
||||||
}
|
}
|
||||||
sname = new PrincipalName(sname.getNameType(),
|
sname = new PrincipalName(sname.getNameType(),
|
||||||
sname.getNameStrings(), new Realm(uRealm));
|
sname.getNameStrings(), new Realm(uRealm));
|
||||||
}
|
}
|
||||||
Credentials creds = serviceCreds(
|
Credentials creds = serviceCreds(
|
||||||
KDCOptions.with(KDCOptions.FORWARDABLE),
|
KDCOptions.with(KDCOptions.FORWARDABLE),
|
||||||
ccreds, ccreds.getClient(), sname, user,
|
middleTGT, middleTGT.getClient(), sname, user,
|
||||||
null, new PAData[] {
|
null, new PAData[] {
|
||||||
new PAData(Krb5.PA_FOR_USER,
|
new PAData(Krb5.PA_FOR_USER,
|
||||||
new PAForUserEnc(user,
|
new PAForUserEnc(user,
|
||||||
ccreds.getSessionKey()).asn1Encode()),
|
middleTGT.getSessionKey()).asn1Encode()),
|
||||||
new PAData(Krb5.PA_PAC_OPTIONS,
|
new PAData(Krb5.PA_PAC_OPTIONS,
|
||||||
new PaPacOptions()
|
new PaPacOptions()
|
||||||
.setResourceBasedConstrainedDelegation(true)
|
.setResourceBasedConstrainedDelegation(true)
|
||||||
@ -101,7 +97,7 @@ public class CredentialsUtil {
|
|||||||
if (!creds.getClient().equals(user)) {
|
if (!creds.getClient().equals(user)) {
|
||||||
throw new KrbException("S4U2self request not honored by KDC");
|
throw new KrbException("S4U2self request not honored by KDC");
|
||||||
}
|
}
|
||||||
if (!creds.isForwardable()) {
|
if (!creds.isForwardable() && !Credentials.S4U2PROXY_ACCEPT_NON_FORWARDABLE) {
|
||||||
throw new KrbException("S4U2self ticket must be FORWARDABLE");
|
throw new KrbException("S4U2self ticket must be FORWARDABLE");
|
||||||
}
|
}
|
||||||
return creds;
|
return creds;
|
||||||
@ -111,17 +107,17 @@ public class CredentialsUtil {
|
|||||||
* Used by a middle server to acquire a service ticket to a backend
|
* Used by a middle server to acquire a service ticket to a backend
|
||||||
* server using the S4U2proxy extension.
|
* server using the S4U2proxy extension.
|
||||||
* @param backend the name of the backend service
|
* @param backend the name of the backend service
|
||||||
* @param second the client's service ticket to the middle server
|
* @param userCreds containing the user's service ticket to the middle server
|
||||||
* @param ccreds the TGT of the middle server
|
* @param middleTGT the TGT of the middle server
|
||||||
* @return the creds (cname=client, sname=backend)
|
* @return the creds (cname=user, sname=backend)
|
||||||
*/
|
*/
|
||||||
public static Credentials acquireS4U2proxyCreds(
|
public static Credentials acquireS4U2proxyCreds(
|
||||||
String backend, Ticket second,
|
String backend, Credentials userCreds,
|
||||||
PrincipalName client, Credentials ccreds)
|
PrincipalName client, Credentials middleTGT)
|
||||||
throws KrbException, IOException {
|
throws KrbException, IOException {
|
||||||
PrincipalName backendPrincipal = new PrincipalName(backend);
|
PrincipalName backendPrincipal = new PrincipalName(backend);
|
||||||
String backendRealm = backendPrincipal.getRealmString();
|
String backendRealm = backendPrincipal.getRealmString();
|
||||||
String localRealm = ccreds.getClient().getRealmString();
|
String localRealm = middleTGT.getClient().getRealmString();
|
||||||
if (!backendRealm.equals(localRealm)) {
|
if (!backendRealm.equals(localRealm)) {
|
||||||
// The middle service and the backend service are on
|
// The middle service and the backend service are on
|
||||||
// different realms, so referrals will be required.
|
// different realms, so referrals will be required.
|
||||||
@ -136,8 +132,8 @@ public class CredentialsUtil {
|
|||||||
}
|
}
|
||||||
Credentials creds = serviceCreds(KDCOptions.with(
|
Credentials creds = serviceCreds(KDCOptions.with(
|
||||||
KDCOptions.CNAME_IN_ADDL_TKT, KDCOptions.FORWARDABLE),
|
KDCOptions.CNAME_IN_ADDL_TKT, KDCOptions.FORWARDABLE),
|
||||||
ccreds, ccreds.getClient(), backendPrincipal, null,
|
middleTGT, middleTGT.getClient(), backendPrincipal, null,
|
||||||
new Ticket[] {second}, new PAData[] {
|
userCreds, new PAData[] {
|
||||||
new PAData(Krb5.PA_PAC_OPTIONS,
|
new PAData(Krb5.PA_PAC_OPTIONS,
|
||||||
new PaPacOptions()
|
new PaPacOptions()
|
||||||
.setResourceBasedConstrainedDelegation(true)
|
.setResourceBasedConstrainedDelegation(true)
|
||||||
@ -159,28 +155,30 @@ public class CredentialsUtil {
|
|||||||
* from the foreign KDC.
|
* from the foreign KDC.
|
||||||
*
|
*
|
||||||
* @param service the name of service principal
|
* @param service the name of service principal
|
||||||
* @param ccreds client's initial credential
|
* @param initCreds client's initial credential
|
||||||
*/
|
*/
|
||||||
public static Credentials acquireServiceCreds(
|
public static Credentials acquireServiceCreds(
|
||||||
String service, Credentials ccreds)
|
String service, Credentials initCreds)
|
||||||
throws KrbException, IOException {
|
throws KrbException, IOException {
|
||||||
PrincipalName sname = new PrincipalName(service,
|
return serviceCreds(new KDCOptions(), initCreds,
|
||||||
PrincipalName.KRB_NT_UNKNOWN);
|
initCreds.getClient(),
|
||||||
return serviceCreds(sname, ccreds);
|
new PrincipalName(service, PrincipalName.KRB_NT_UNKNOWN),
|
||||||
|
null, null,
|
||||||
|
null, S4U2Type.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a TGT to another realm
|
* Gets a TGT to another realm
|
||||||
* @param localRealm this realm
|
* @param localRealm this realm
|
||||||
* @param serviceRealm the other realm, cannot equals to localRealm
|
* @param serviceRealm the other realm, cannot equals to localRealm
|
||||||
* @param ccreds TGT in this realm
|
* @param localTGT TGT in this realm
|
||||||
* @param okAsDelegate an [out] argument to receive the okAsDelegate
|
* @param okAsDelegate an [out] argument to receive the okAsDelegate
|
||||||
* property. True only if all realms allow delegation.
|
* property. True only if all realms allow delegation.
|
||||||
* @return the TGT for the other realm, null if cannot find a path
|
* @return the TGT for the other realm, null if cannot find a path
|
||||||
* @throws KrbException if something goes wrong
|
* @throws KrbException if something goes wrong
|
||||||
*/
|
*/
|
||||||
private static Credentials getTGTforRealm(String localRealm,
|
private static Credentials getTGTforRealm(String localRealm,
|
||||||
String serviceRealm, Credentials ccreds, boolean[] okAsDelegate)
|
String serviceRealm, Credentials localTGT, boolean[] okAsDelegate)
|
||||||
throws KrbException {
|
throws KrbException {
|
||||||
|
|
||||||
// Get a list of realms to traverse
|
// Get a list of realms to traverse
|
||||||
@ -192,7 +190,7 @@ public class CredentialsUtil {
|
|||||||
String newTgtRealm = null;
|
String newTgtRealm = null;
|
||||||
|
|
||||||
okAsDelegate[0] = true;
|
okAsDelegate[0] = true;
|
||||||
for (cTgt = ccreds, i = 0; i < realms.length;) {
|
for (cTgt = localTGT, i = 0; i < realms.length;) {
|
||||||
tempService = PrincipalName.tgsService(serviceRealm, realms[i]);
|
tempService = PrincipalName.tgsService(serviceRealm, realms[i]);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -309,10 +307,10 @@ public class CredentialsUtil {
|
|||||||
* This method does the real job to request the service credential.
|
* This method does the real job to request the service credential.
|
||||||
*/
|
*/
|
||||||
private static Credentials serviceCreds(
|
private static Credentials serviceCreds(
|
||||||
PrincipalName service, Credentials ccreds)
|
PrincipalName service, Credentials initCreds)
|
||||||
throws KrbException, IOException {
|
throws KrbException, IOException {
|
||||||
return serviceCreds(new KDCOptions(), ccreds,
|
return serviceCreds(new KDCOptions(), initCreds,
|
||||||
ccreds.getClient(), service, null, null,
|
initCreds.getClient(), service, null, null,
|
||||||
null, S4U2Type.NONE);
|
null, S4U2Type.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,13 +323,13 @@ public class CredentialsUtil {
|
|||||||
private static Credentials serviceCreds(
|
private static Credentials serviceCreds(
|
||||||
KDCOptions options, Credentials asCreds,
|
KDCOptions options, Credentials asCreds,
|
||||||
PrincipalName cname, PrincipalName sname,
|
PrincipalName cname, PrincipalName sname,
|
||||||
PrincipalName user, Ticket[] additionalTickets,
|
PrincipalName user, Credentials additionalCreds,
|
||||||
PAData[] extraPAs, S4U2Type s4u2Type)
|
PAData[] extraPAs, S4U2Type s4u2Type)
|
||||||
throws KrbException, IOException {
|
throws KrbException, IOException {
|
||||||
if (!Config.DISABLE_REFERRALS) {
|
if (!Config.DISABLE_REFERRALS) {
|
||||||
try {
|
try {
|
||||||
return serviceCredsReferrals(options, asCreds, cname, sname,
|
return serviceCredsReferrals(options, asCreds, cname, sname,
|
||||||
s4u2Type, user, additionalTickets, extraPAs);
|
s4u2Type, user, additionalCreds, extraPAs);
|
||||||
} catch (KrbException e) {
|
} catch (KrbException e) {
|
||||||
// Server may raise an error if CANONICALIZE is true.
|
// Server may raise an error if CANONICALIZE is true.
|
||||||
// Try CANONICALIZE false.
|
// Try CANONICALIZE false.
|
||||||
@ -339,7 +337,7 @@ public class CredentialsUtil {
|
|||||||
}
|
}
|
||||||
return serviceCredsSingle(options, asCreds, cname,
|
return serviceCredsSingle(options, asCreds, cname,
|
||||||
asCreds.getClientAlias(), sname, sname, s4u2Type,
|
asCreds.getClientAlias(), sname, sname, s4u2Type,
|
||||||
user, additionalTickets, extraPAs);
|
user, additionalCreds, extraPAs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -350,7 +348,7 @@ public class CredentialsUtil {
|
|||||||
KDCOptions options, Credentials asCreds,
|
KDCOptions options, Credentials asCreds,
|
||||||
PrincipalName cname, PrincipalName sname,
|
PrincipalName cname, PrincipalName sname,
|
||||||
S4U2Type s4u2Type, PrincipalName user,
|
S4U2Type s4u2Type, PrincipalName user,
|
||||||
Ticket[] additionalTickets, PAData[] extraPAs)
|
Credentials additionalCreds, PAData[] extraPAs)
|
||||||
throws KrbException, IOException {
|
throws KrbException, IOException {
|
||||||
options = new KDCOptions(options.toBooleanArray());
|
options = new KDCOptions(options.toBooleanArray());
|
||||||
options.set(KDCOptions.CANONICALIZE, true);
|
options.set(KDCOptions.CANONICALIZE, true);
|
||||||
@ -363,12 +361,12 @@ public class CredentialsUtil {
|
|||||||
while (referrals.size() <= Config.MAX_REFERRALS) {
|
while (referrals.size() <= Config.MAX_REFERRALS) {
|
||||||
ReferralsCache.ReferralCacheEntry ref =
|
ReferralsCache.ReferralCacheEntry ref =
|
||||||
ReferralsCache.get(cname, sname, user,
|
ReferralsCache.get(cname, sname, user,
|
||||||
additionalTickets, refSname.getRealmString());
|
additionalCreds, refSname.getRealmString());
|
||||||
String toRealm = null;
|
String toRealm = null;
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
creds = serviceCredsSingle(options, asCreds, cname,
|
creds = serviceCredsSingle(options, asCreds, cname,
|
||||||
clientAlias, refSname, cSname, s4u2Type,
|
clientAlias, refSname, cSname, s4u2Type,
|
||||||
user, additionalTickets, extraPAs);
|
user, additionalCreds, extraPAs);
|
||||||
PrincipalName server = creds.getServer();
|
PrincipalName server = creds.getServer();
|
||||||
if (!refSname.equals(server)) {
|
if (!refSname.equals(server)) {
|
||||||
String[] serverNameStrings = server.getNameStrings();
|
String[] serverNameStrings = server.getNameStrings();
|
||||||
@ -380,7 +378,7 @@ public class CredentialsUtil {
|
|||||||
// Server Name (sname) has the following format:
|
// Server Name (sname) has the following format:
|
||||||
// krbtgt/TO-REALM.COM@FROM-REALM.COM
|
// krbtgt/TO-REALM.COM@FROM-REALM.COM
|
||||||
ReferralsCache.put(cname, sname, user,
|
ReferralsCache.put(cname, sname, user,
|
||||||
additionalTickets, server.getRealmString(),
|
additionalCreds, server.getRealmString(),
|
||||||
serverNameStrings[1], creds);
|
serverNameStrings[1], creds);
|
||||||
toRealm = serverNameStrings[1];
|
toRealm = serverNameStrings[1];
|
||||||
isReferral = true;
|
isReferral = true;
|
||||||
@ -398,13 +396,11 @@ public class CredentialsUtil {
|
|||||||
toRealm = handleS4U2ProxyReferral(asCreds,
|
toRealm = handleS4U2ProxyReferral(asCreds,
|
||||||
credsInOut, sname);
|
credsInOut, sname);
|
||||||
creds = credsInOut[0];
|
creds = credsInOut[0];
|
||||||
if (additionalTickets == null ||
|
if (additionalCreds == null || credsInOut[1] == null) {
|
||||||
additionalTickets.length == 0 ||
|
|
||||||
credsInOut[1] == null) {
|
|
||||||
throw new KrbException("Additional tickets expected" +
|
throw new KrbException("Additional tickets expected" +
|
||||||
" for S4U2Proxy.");
|
" for S4U2Proxy.");
|
||||||
}
|
}
|
||||||
additionalTickets[0] = credsInOut[1].getTicket();
|
additionalCreds = credsInOut[1];
|
||||||
} else if (s4u2Type == S4U2Type.SELF) {
|
} else if (s4u2Type == S4U2Type.SELF) {
|
||||||
handleS4U2SelfReferral(extraPAs, user, creds);
|
handleS4U2SelfReferral(extraPAs, user, creds);
|
||||||
}
|
}
|
||||||
@ -436,7 +432,7 @@ public class CredentialsUtil {
|
|||||||
PrincipalName cname, PrincipalName clientAlias,
|
PrincipalName cname, PrincipalName clientAlias,
|
||||||
PrincipalName refSname, PrincipalName sname,
|
PrincipalName refSname, PrincipalName sname,
|
||||||
S4U2Type s4u2Type, PrincipalName user,
|
S4U2Type s4u2Type, PrincipalName user,
|
||||||
Ticket[] additionalTickets, PAData[] extraPAs)
|
Credentials additionalCreds, PAData[] extraPAs)
|
||||||
throws KrbException, IOException {
|
throws KrbException, IOException {
|
||||||
Credentials theCreds = null;
|
Credentials theCreds = null;
|
||||||
boolean[] okAsDelegate = new boolean[]{true};
|
boolean[] okAsDelegate = new boolean[]{true};
|
||||||
@ -473,7 +469,7 @@ public class CredentialsUtil {
|
|||||||
" same realm");
|
" same realm");
|
||||||
}
|
}
|
||||||
KrbTgsReq req = new KrbTgsReq(options, asCreds, cname, clientAlias,
|
KrbTgsReq req = new KrbTgsReq(options, asCreds, cname, clientAlias,
|
||||||
refSname, sname, additionalTickets, extraPAs);
|
refSname, sname, additionalCreds, extraPAs);
|
||||||
theCreds = req.sendAndGetCreds();
|
theCreds = req.sendAndGetCreds();
|
||||||
if (theCreds != null) {
|
if (theCreds != null) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
package sun.security.krb5.internal;
|
package sun.security.krb5.internal;
|
||||||
|
|
||||||
import sun.security.krb5.*;
|
import sun.security.krb5.*;
|
||||||
import java.util.Vector;
|
|
||||||
import sun.security.util.*;
|
import sun.security.util.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
@ -192,8 +191,4 @@ public class KDCReq {
|
|||||||
true, (byte) msgType), bytes);
|
true, (byte) msgType), bytes);
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] asn1EncodeReqBody() throws Asn1Exception, IOException {
|
|
||||||
return reqBody.asn1Encode(msgType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -112,10 +112,10 @@ final class ReferralsCache {
|
|||||||
* REALM-1.COM -> REALM-2.COM referral entry is removed from the cache.
|
* REALM-1.COM -> REALM-2.COM referral entry is removed from the cache.
|
||||||
*/
|
*/
|
||||||
static synchronized void put(PrincipalName cname, PrincipalName service,
|
static synchronized void put(PrincipalName cname, PrincipalName service,
|
||||||
PrincipalName user, Ticket[] userSvcTickets, String fromRealm,
|
PrincipalName user, Credentials additionalCreds, String fromRealm,
|
||||||
String toRealm, Credentials creds) {
|
String toRealm, Credentials creds) {
|
||||||
Ticket userSvcTicket = (userSvcTickets != null ?
|
Ticket userSvcTicket = (additionalCreds != null ?
|
||||||
userSvcTickets[0] : null);
|
additionalCreds.getTicket() : null);
|
||||||
ReferralCacheKey k = new ReferralCacheKey(cname, service,
|
ReferralCacheKey k = new ReferralCacheKey(cname, service,
|
||||||
user, userSvcTicket);
|
user, userSvcTicket);
|
||||||
pruneExpired(k);
|
pruneExpired(k);
|
||||||
@ -152,9 +152,9 @@ final class ReferralsCache {
|
|||||||
*/
|
*/
|
||||||
static synchronized ReferralCacheEntry get(PrincipalName cname,
|
static synchronized ReferralCacheEntry get(PrincipalName cname,
|
||||||
PrincipalName service, PrincipalName user,
|
PrincipalName service, PrincipalName user,
|
||||||
Ticket[] userSvcTickets, String fromRealm) {
|
Credentials additionalCreds, String fromRealm) {
|
||||||
Ticket userSvcTicket = (userSvcTickets != null ?
|
Ticket userSvcTicket = (additionalCreds != null ?
|
||||||
userSvcTickets[0] : null);
|
additionalCreds.getTicket() : null);
|
||||||
ReferralCacheKey k = new ReferralCacheKey(cname, service,
|
ReferralCacheKey k = new ReferralCacheKey(cname, service,
|
||||||
user, userSvcTicket);
|
user, userSvcTicket);
|
||||||
pruneExpired(k);
|
pruneExpired(k);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -29,8 +29,11 @@ import java.lang.reflect.InvocationTargetException;
|
|||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -249,6 +252,14 @@ public class KDC {
|
|||||||
* If true, will check if TGS-REQ contains a non-null addresses field.
|
* If true, will check if TGS-REQ contains a non-null addresses field.
|
||||||
*/
|
*/
|
||||||
CHECK_ADDRESSES,
|
CHECK_ADDRESSES,
|
||||||
|
/**
|
||||||
|
* If true, S4U2self ticket is not set forwardable.
|
||||||
|
*/
|
||||||
|
S4U2SELF_NOT_FORWARDABLE,
|
||||||
|
/**
|
||||||
|
* If true, allow S4U2self ticket not forwardable.
|
||||||
|
*/
|
||||||
|
S4U2SELF_ALLOW_NOT_FORWARDABLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -441,12 +452,12 @@ public class KDC {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new principal to this realm with a random password
|
* Adds a new principal to this realm with a generated password
|
||||||
* @param user the principal's name. For a service principal, use the
|
* @param user the principal's name. For a service principal, use the
|
||||||
* form of host/f.q.d.n
|
* form of host/f.q.d.n
|
||||||
*/
|
*/
|
||||||
public void addPrincipalRandKey(String user) {
|
public void addPrincipalRandKey(String user) {
|
||||||
addPrincipal(user, randomPassword());
|
addPrincipal(user, randomPassword(user + "@" + realm));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -607,14 +618,29 @@ public class KDC {
|
|||||||
startServer(port, asDaemon);
|
startServer(port, asDaemon);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Generates a 32-char random password
|
* Generates a 32-char password
|
||||||
|
* @param user the string to generate from, random is null
|
||||||
* @return the password
|
* @return the password
|
||||||
*/
|
*/
|
||||||
private static char[] randomPassword() {
|
private static char[] randomPassword(String user) {
|
||||||
char[] pass = new char[32];
|
char[] pass;
|
||||||
|
if (user == null) {
|
||||||
|
pass = new char[32];
|
||||||
Random r = new Random();
|
Random r = new Random();
|
||||||
for (int i=0; i<31; i++)
|
for (int i = 0; i < 31; i++) {
|
||||||
pass[i] = (char) ('a' + r.nextInt(26));
|
pass[i] = (char) ('a' + r.nextInt(26));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
pass = Base64.getEncoder().encodeToString(
|
||||||
|
MessageDigest.getInstance("SHA-256").digest((user)
|
||||||
|
.getBytes(StandardCharsets.UTF_8)))
|
||||||
|
.substring(0, 32)
|
||||||
|
.toCharArray();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
// The last char cannot be a number, otherwise, keyForUser()
|
// The last char cannot be a number, otherwise, keyForUser()
|
||||||
// believes it's a sign of kvno
|
// believes it's a sign of kvno
|
||||||
pass[31] = 'Z';
|
pass[31] = 'Z';
|
||||||
@ -629,7 +655,7 @@ public class KDC {
|
|||||||
*/
|
*/
|
||||||
private static EncryptionKey generateRandomKey(int eType)
|
private static EncryptionKey generateRandomKey(int eType)
|
||||||
throws KrbException {
|
throws KrbException {
|
||||||
return genKey0(randomPassword(), "NOTHING", null, eType, null);
|
return genKey0(randomPassword(null), "NOTHING", null, eType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -790,7 +816,7 @@ public class KDC {
|
|||||||
service.getNameStrings(), service.getRealm());
|
service.getNameStrings(), service.getRealm());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
System.out.println(realm + "> " + tgsReq.reqBody.cname +
|
log(tgsReq.reqBody.cname +
|
||||||
" sends TGS-REQ for " +
|
" sends TGS-REQ for " +
|
||||||
service + ", " + tgsReq.reqBody.kdcOptions);
|
service + ", " + tgsReq.reqBody.kdcOptions);
|
||||||
KDCReqBody body = tgsReq.reqBody;
|
KDCReqBody body = tgsReq.reqBody;
|
||||||
@ -810,7 +836,7 @@ public class KDC {
|
|||||||
boolean allowForwardable = true;
|
boolean allowForwardable = true;
|
||||||
boolean isReferral = false;
|
boolean isReferral = false;
|
||||||
if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) {
|
if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) {
|
||||||
System.out.println(realm + "> verifying referral for " +
|
log("verifying referral for " +
|
||||||
body.sname.getNameString());
|
body.sname.getNameString());
|
||||||
KDC referral = aliasReferrals.get(body.sname.getNameString());
|
KDC referral = aliasReferrals.get(body.sname.getNameString());
|
||||||
if (referral != null) {
|
if (referral != null) {
|
||||||
@ -819,7 +845,7 @@ public class KDC {
|
|||||||
PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
|
PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
|
||||||
referral.getRealm(), PrincipalName.KRB_NT_SRV_INST,
|
referral.getRealm(), PrincipalName.KRB_NT_SRV_INST,
|
||||||
this.getRealm());
|
this.getRealm());
|
||||||
System.out.println(realm + "> referral to " +
|
log("referral to " +
|
||||||
referral.getRealm());
|
referral.getRealm());
|
||||||
isReferral = true;
|
isReferral = true;
|
||||||
}
|
}
|
||||||
@ -842,14 +868,14 @@ public class KDC {
|
|||||||
// Finally, cname will be overwritten by PA-FOR-USER
|
// Finally, cname will be overwritten by PA-FOR-USER
|
||||||
// if it exists.
|
// if it exists.
|
||||||
cname = etp.cname;
|
cname = etp.cname;
|
||||||
System.out.println(realm + "> presenting a ticket of "
|
log("presenting a ticket of "
|
||||||
+ etp.cname + " to " + tkt.sname);
|
+ etp.cname + " to " + tkt.sname);
|
||||||
} else if (pa.getType() == Krb5.PA_FOR_USER) {
|
} else if (pa.getType() == Krb5.PA_FOR_USER) {
|
||||||
if (options.containsKey(Option.ALLOW_S4U2SELF)) {
|
if (options.containsKey(Option.ALLOW_S4U2SELF)) {
|
||||||
PAForUserEnc p4u = new PAForUserEnc(
|
PAForUserEnc p4u = new PAForUserEnc(
|
||||||
new DerValue(pa.getValue()), null);
|
new DerValue(pa.getValue()), null);
|
||||||
forUserCName = p4u.name;
|
forUserCName = p4u.name;
|
||||||
System.out.println(realm + "> See PA_FOR_USER "
|
log("See PA_FOR_USER "
|
||||||
+ " in the name of " + p4u.name);
|
+ " in the name of " + p4u.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -862,6 +888,9 @@ public class KDC {
|
|||||||
// allowed to send S4U2self, do not send an error.
|
// allowed to send S4U2self, do not send an error.
|
||||||
// Instead, send a ticket which is useless later.
|
// Instead, send a ticket which is useless later.
|
||||||
allowForwardable = false;
|
allowForwardable = false;
|
||||||
|
} else if (options.get(Option.S4U2SELF_NOT_FORWARDABLE) == Boolean.TRUE) {
|
||||||
|
// Requsted not forwardable
|
||||||
|
allowForwardable = false;
|
||||||
}
|
}
|
||||||
cname = forUserCName;
|
cname = forUserCName;
|
||||||
}
|
}
|
||||||
@ -936,15 +965,16 @@ public class KDC {
|
|||||||
DerInputStream derIn = new DerInputStream(bb);
|
DerInputStream derIn = new DerInputStream(bb);
|
||||||
DerValue der = derIn.getDerValue();
|
DerValue der = derIn.getDerValue();
|
||||||
EncTicketPart tktEncPart = new EncTicketPart(der.toByteArray());
|
EncTicketPart tktEncPart = new EncTicketPart(der.toByteArray());
|
||||||
if (!tktEncPart.flags.get(Krb5.TKT_OPTS_FORWARDABLE)) {
|
if (!tktEncPart.flags.get(Krb5.TKT_OPTS_FORWARDABLE)
|
||||||
//throw new KrbException(Krb5.KDC_ERR_BADOPTION);
|
&& options.get(Option.S4U2SELF_ALLOW_NOT_FORWARDABLE) != Boolean.TRUE) {
|
||||||
|
throw new KrbException(Krb5.KDC_ERR_BADOPTION);
|
||||||
}
|
}
|
||||||
PrincipalName client = tktEncPart.cname;
|
PrincipalName client = tktEncPart.cname;
|
||||||
System.out.println(realm + "> and an additional ticket of "
|
log("and an additional ticket of "
|
||||||
+ client + " to " + second.sname);
|
+ client + " to " + second.sname);
|
||||||
if (map.containsKey(cname.toString())) {
|
if (map.containsKey(cname.toString())) {
|
||||||
if (map.get(cname.toString()).contains(service.toString())) {
|
if (map.get(cname.toString()).contains(service.toString())) {
|
||||||
System.out.println(realm + "> S4U2proxy OK");
|
log("S4U2proxy OK");
|
||||||
} else {
|
} else {
|
||||||
throw new KrbException(Krb5.KDC_ERR_BADOPTION);
|
throw new KrbException(Krb5.KDC_ERR_BADOPTION);
|
||||||
}
|
}
|
||||||
@ -1066,7 +1096,7 @@ public class KDC {
|
|||||||
Realm.getDefault());
|
Realm.getDefault());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
System.out.println(realm + "> " + asReq.reqBody.cname +
|
log(asReq.reqBody.cname +
|
||||||
" sends AS-REQ for " +
|
" sends AS-REQ for " +
|
||||||
service + ", " + asReq.reqBody.kdcOptions);
|
service + ", " + asReq.reqBody.kdcOptions);
|
||||||
|
|
||||||
@ -1601,6 +1631,10 @@ public class KDC {
|
|||||||
return udpConsumerReady && tcpConsumerReady && dispatcherReady;
|
return udpConsumerReady && tcpConsumerReady && dispatcherReady;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void log(String s) {
|
||||||
|
System.out.println(realm + ":" + port + "> " + s);
|
||||||
|
}
|
||||||
|
|
||||||
public void terminate() {
|
public void terminate() {
|
||||||
if (nativeKdc != null) {
|
if (nativeKdc != null) {
|
||||||
System.out.println("Killing kdc...");
|
System.out.println("Killing kdc...");
|
||||||
|
96
test/jdk/sun/security/krb5/auto/S4U2selfNotF.java
Normal file
96
test/jdk/sun/security/krb5/auto/S4U2selfNotF.java
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, 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 8272162
|
||||||
|
* @summary S4U2Self ticket without forwardable flag
|
||||||
|
* @library /test/lib
|
||||||
|
* @compile -XDignore.symbol.file S4U2selfNotF.java
|
||||||
|
* @run main jdk.test.lib.FileInstaller TestHosts TestHosts
|
||||||
|
* @run main/othervm -Djdk.net.hosts.file=TestHosts
|
||||||
|
* -Djdk.security.krb5.s4u2proxy.acceptNonForwardableServiceTicket=true
|
||||||
|
* S4U2selfNotF
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
import sun.security.jgss.GSSUtil;
|
||||||
|
import sun.security.krb5.Config;
|
||||||
|
|
||||||
|
public class S4U2selfNotF {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
// Create 2 KDCs that has almost the same settings
|
||||||
|
OneKDC[] kdcs = new OneKDC[2];
|
||||||
|
boolean[] touched = new boolean[2];
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
final int pos = i;
|
||||||
|
kdcs[i] = new OneKDC(null) {
|
||||||
|
protected byte[] processTgsReq(byte[] in) throws Exception {
|
||||||
|
touched[pos] = true;
|
||||||
|
return super.processTgsReq(in);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
kdcs[i].setOption(KDC.Option.ALLOW_S4U2SELF,
|
||||||
|
List.of(OneKDC.USER + "@" + OneKDC.REALM));
|
||||||
|
kdcs[i].setOption(KDC.Option.ALLOW_S4U2PROXY, Map.of(
|
||||||
|
OneKDC.USER + "@" + OneKDC.REALM,
|
||||||
|
List.of(OneKDC.BACKEND + "@" + OneKDC.REALM)));
|
||||||
|
}
|
||||||
|
kdcs[0].writeJAASConf();
|
||||||
|
|
||||||
|
// except that the 1st issues a non-forwardable S4U2self
|
||||||
|
// ticket and only the 2nd accepts it
|
||||||
|
kdcs[0].setOption(KDC.Option.S4U2SELF_NOT_FORWARDABLE, true);
|
||||||
|
kdcs[1].setOption(KDC.Option.S4U2SELF_ALLOW_NOT_FORWARDABLE, true);
|
||||||
|
|
||||||
|
Files.write(Path.of(OneKDC.KRB5_CONF), String.format("""
|
||||||
|
[libdefaults]
|
||||||
|
default_realm = RABBIT.HOLE
|
||||||
|
forwardable = true
|
||||||
|
default_keytab_name = localkdc.ktab
|
||||||
|
|
||||||
|
[realms]
|
||||||
|
RABBIT.HOLE = {
|
||||||
|
kdc = kdc.rabbit.hole:%d kdc.rabbit.hole:%d
|
||||||
|
}
|
||||||
|
""", kdcs[0].getPort(), kdcs[1].getPort())
|
||||||
|
.getBytes(StandardCharsets.UTF_8));
|
||||||
|
Config.refresh();
|
||||||
|
|
||||||
|
Context c = Context.fromJAAS("client");
|
||||||
|
c = c.impersonate(OneKDC.USER2);
|
||||||
|
c.startAsClient(OneKDC.BACKEND, GSSUtil.GSS_KRB5_MECH_OID);
|
||||||
|
c.take(new byte[0]);
|
||||||
|
|
||||||
|
Asserts.assertTrue(touched[0]); // get S4U2self from 1st one
|
||||||
|
Asserts.assertTrue(touched[1]); // get S4U2proxy from 2nd one
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user