diff options
author | andrew <unknown> | 2020-01-12 03:05:17 +0000 |
---|---|---|
committer | bell-sw <liberica@bell-sw.com> | 2020-01-19 09:13:18 +0300 |
commit | a805c64b2e8d63e6ac9854426ca6dc8189031c72 (patch) | |
tree | 6077bc974a1378d158adc9338c1cbad7752c2634 /test | |
parent | 0e1b8b9b1580ffff34b0d54e8534cc85b5ea4d6e (diff) | |
download | jdk8u_jdk-a805c64b2e8d63e6ac9854426ca6dc8189031c72.tar.gz |
8227437: S4U2proxy cannot continue because server's TGT cannot be found
Reviewed-by: mbalao
Diffstat (limited to 'test')
-rw-r--r-- | test/sun/security/krb5/auto/KDC.java | 13 | ||||
-rw-r--r-- | test/sun/security/krb5/auto/ReferralsTest.java | 194 |
2 files changed, 146 insertions, 61 deletions
diff --git a/test/sun/security/krb5/auto/KDC.java b/test/sun/security/krb5/auto/KDC.java index 247d418453..9e9cd977bb 100644 --- a/test/sun/security/krb5/auto/KDC.java +++ b/test/sun/security/krb5/auto/KDC.java @@ -804,8 +804,10 @@ public class KDC { PrincipalName cname = null; boolean allowForwardable = true; - + boolean isReferral = false; if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) { + System.out.println(realm + "> verifying referral for " + + body.sname.getNameString()); KDC referral = aliasReferrals.get(body.sname.getNameString()); if (referral != null) { service = new PrincipalName( @@ -813,6 +815,9 @@ public class KDC { PrincipalName.NAME_COMPONENT_SEPARATOR_STR + referral.getRealm(), PrincipalName.KRB_NT_SRV_INST, this.getRealm()); + System.out.println(realm + "> referral to " + + referral.getRealm()); + isReferral = true; } } @@ -912,7 +917,8 @@ 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 (body.kdcOptions.get(KDCOptions.CNAME_IN_ADDL_TKT) && + !isReferral) { if (!options.containsKey(Option.ALLOW_S4U2PROXY)) { // Don't understand CNAME_IN_ADDL_TKT throw new KrbException(Krb5.KDC_ERR_BADOPTION); @@ -1073,8 +1079,7 @@ public class KDC { } int eType = eTypes[0]; - if (body.kdcOptions.get(KDCOptions.CANONICALIZE) && - body.cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) { + if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) { PrincipalName principal = alias2Principals.get( body.cname.getNameString()); if (principal != null) { diff --git a/test/sun/security/krb5/auto/ReferralsTest.java b/test/sun/security/krb5/auto/ReferralsTest.java index 9fc87b7e06..32e56344f6 100644 --- a/test/sun/security/krb5/auto/ReferralsTest.java +++ b/test/sun/security/krb5/auto/ReferralsTest.java @@ -29,9 +29,18 @@ */ import java.io.File; -import sun.security.krb5.Credentials; -import sun.security.krb5.internal.CredentialsUtil; -import sun.security.krb5.KrbAsReqBuilder; +import java.security.Principal; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.security.auth.kerberos.KerberosTicket; +import javax.security.auth.Subject; + +import org.ietf.jgss.GSSName; + +import sun.security.jgss.GSSUtil; import sun.security.krb5.PrincipalName; public class ReferralsTest { @@ -40,39 +49,32 @@ public class ReferralsTest { private static final String realmKDC1 = "RABBIT.HOLE"; private static final String realmKDC2 = "DEV.RABBIT.HOLE"; private static final char[] password = "123qwe@Z".toCharArray(); + + // Names private static final String clientName = "test"; + private static final String serviceName = "http" + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + + "server.dev.rabbit.hole"; + // Alias private static final String clientAlias = clientName + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1; - private static final String clientKDC1QueryName = clientAlias.replaceAll( + // Names + realms + private static final String clientKDC1Name = clientAlias.replaceAll( PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" + PrincipalName.NAME_REALM_SEPARATOR_STR) + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1; - private static PrincipalName clientKDC1QueryPrincipal = null; - static { - try { - clientKDC1QueryPrincipal = new PrincipalName( - clientKDC1QueryName, PrincipalName.KRB_NT_ENTERPRISE, - null); - } catch (Throwable t) {} - } - private static final String clientKDC2Name = clientName + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2; - - private static final String serviceName = "http" + - PrincipalName.NAME_COMPONENT_SEPARATOR_STR + - "server.dev.rabbit.hole"; - - private static Credentials tgt; - private static Credentials tgs; + private static final String serviceKDC2Name = serviceName + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2; public static void main(String[] args) throws Exception { try { initializeKDCs(); - getTGT(); - getTGS(); + testSubjectCredentials(); + testDelegated(); } finally { cleanup(); } @@ -107,6 +109,11 @@ public class ReferralsTest { kdc1.registerAlias(serviceName, kdc2); kdc2.registerAlias(clientAlias, clientKDC2Name); + Map<String,List<String>> mapKDC2 = new HashMap<>(); + mapKDC2.put(serviceName + "@" + realmKDC2, Arrays.asList( + new String[]{serviceName + "@" + realmKDC2})); + kdc2.setOption(KDC.Option.ALLOW_S4U2PROXY, mapKDC2); + KDC.saveConfig(krbConfigName, kdc1, kdc2, "forwardable=true"); System.setProperty("java.security.krb5.conf", krbConfigName); @@ -119,50 +126,123 @@ public class ReferralsTest { } } - private static void getTGT() throws Exception { - KrbAsReqBuilder builder = new KrbAsReqBuilder(clientKDC1QueryPrincipal, - password); - tgt = builder.action().getCreds(); - builder.destroy(); + /* + * The client subject (whose principal is + * test@RABBIT.HOLE@RABBIT.HOLE) will obtain a TGT after + * realm referral and name canonicalization (TGT cname + * will be test@DEV.RABBIT.HOLE). With this TGT, the client will request + * a TGS for service http/server.dev.rabbit.hole@RABBIT.HOLE. After + * realm referral, a http/server.dev.rabbit.hole@DEV.RABBIT.HOLE TGS + * will be obtained. + * + * Assert that we get the proper TGT and TGS tickets, and that they are + * associated to the client subject. + * + * Assert that if we request a TGS for the same service again (based on the + * original service name), we don't get a new one but the previous, + * already in the subject credentials. + */ + private static void testSubjectCredentials() throws Exception { + Subject clientSubject = new Subject(); + Context clientContext = Context.fromUserPass(clientSubject, + clientKDC1Name, password, false); + + Set<Principal> clientPrincipals = clientSubject.getPrincipals(); + if (clientPrincipals.size() != 1) { + throw new Exception("Only one client subject principal expected"); + } + Principal clientPrincipal = clientPrincipals.iterator().next(); if (DEBUG) { - System.out.println("TGT"); - System.out.println("----------------------"); - System.out.println(tgt); - System.out.println("----------------------"); + System.out.println("Client subject principal: " + + clientPrincipal.getName()); } - if (tgt == null) { - throw new Exception("TGT is null"); + if (!clientPrincipal.getName().equals(clientKDC1Name)) { + throw new Exception("Unexpected client subject principal."); } - if (!tgt.getClient().getName().equals(clientKDC2Name)) { - throw new Exception("Unexpected TGT client"); + + clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); + clientContext.take(new byte[0]); + Set<KerberosTicket> clientTickets = + clientSubject.getPrivateCredentials(KerberosTicket.class); + boolean tgtFound = false; + boolean tgsFound = false; + for (KerberosTicket clientTicket : clientTickets) { + String cname = clientTicket.getClient().getName(); + String sname = clientTicket.getServer().getName(); + if (cname.equals(clientKDC2Name)) { + if (sname.equals(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + + realmKDC2 + PrincipalName.NAME_REALM_SEPARATOR_STR + + realmKDC2)) { + tgtFound = true; + } else if (sname.equals(serviceKDC2Name)) { + tgsFound = true; + } + } + if (DEBUG) { + System.out.println("Client subject KerberosTicket:"); + System.out.println(clientTicket); + } } - String[] tgtServerNames = tgt.getServer().getNameStrings(); - if (tgtServerNames.length != 2 || !tgtServerNames[0].equals( - PrincipalName.TGS_DEFAULT_SRV_NAME) || - !tgtServerNames[1].equals(realmKDC2) || - !tgt.getServer().getRealmString().equals(realmKDC2)) { - throw new Exception("Unexpected TGT server"); + if (!tgtFound || !tgsFound) { + throw new Exception("client subject tickets (TGT/TGS) not found."); } - } - - private static void getTGS() throws Exception { - tgs = CredentialsUtil.acquireServiceCreds(serviceName + - PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1, tgt); + int numOfTickets = clientTickets.size(); + clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); + clientContext.take(new byte[0]); + clientContext.status(); + int newNumOfTickets = + clientSubject.getPrivateCredentials(KerberosTicket.class).size(); if (DEBUG) { - System.out.println("TGS"); - System.out.println("----------------------"); - System.out.println(tgs); - System.out.println("----------------------"); + System.out.println("client subject number of tickets: " + + numOfTickets); + System.out.println("client subject new number of tickets: " + + newNumOfTickets); + } + if (numOfTickets != newNumOfTickets) { + throw new Exception("Useless client subject TGS request because" + + " TGS was not found in private credentials."); } - if (tgs == null) { - throw new Exception("TGS is null"); + } + + /* + * The server (http/server.dev.rabbit.hole@DEV.RABBIT.HOLE) + * will authenticate on itself on behalf of the client + * (test@DEV.RABBIT.HOLE). Cross-realm referrals will occur + * when requesting different TGTs and TGSs (including the + * request for delegated credentials). + */ + private static void testDelegated() throws Exception { + Context c = Context.fromUserPass(clientKDC2Name, + password, false); + c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); + Context s = Context.fromUserPass(serviceKDC2Name, + password, true); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + Context delegatedContext = s.delegated(); + delegatedContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); + delegatedContext.x().requestMutualAuth(false); + Context s2 = Context.fromUserPass(serviceKDC2Name, + password, true); + s2.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + + // Test authentication + Context.handshake(delegatedContext, s2); + if (!delegatedContext.x().isEstablished() || !s2.x().isEstablished()) { + throw new Exception("Delegated authentication failed"); } - if (!tgs.getClient().getName().equals(clientKDC2Name)) { - throw new Exception("Unexpected TGS client"); + + // Test identities + GSSName contextInitiatorName = delegatedContext.x().getSrcName(); + GSSName contextAcceptorName = delegatedContext.x().getTargName(); + if (DEBUG) { + System.out.println("Context initiator: " + contextInitiatorName); + System.out.println("Context acceptor: " + contextAcceptorName); } - if (!tgs.getServer().getNameString().equals(serviceName) || - !tgs.getServer().getRealmString().equals(realmKDC2)) { - throw new Exception("Unexpected TGS server"); + if (!contextInitiatorName.toString().equals(clientKDC2Name) || + !contextAcceptorName.toString().equals(serviceName)) { + throw new Exception("Unexpected initiator or acceptor names"); } } } |