test/jdk/sun/security/krb5/auto/ReferralsTest.java
changeset 57487 643978a35f6e
parent 55258 d65d3c37232c
child 58679 9c3209ff7550
equal deleted inserted replaced
57486:347804d623fc 57487:643978a35f6e
    28  * @run main/othervm/timeout=120 -Dsun.security.krb5.debug=true ReferralsTest
    28  * @run main/othervm/timeout=120 -Dsun.security.krb5.debug=true ReferralsTest
    29  * @summary Test Kerberos cross-realm referrals (RFC 6806)
    29  * @summary Test Kerberos cross-realm referrals (RFC 6806)
    30  */
    30  */
    31 
    31 
    32 import java.io.File;
    32 import java.io.File;
    33 import sun.security.krb5.Credentials;
    33 import java.security.Principal;
    34 import sun.security.krb5.internal.CredentialsUtil;
    34 import java.util.Arrays;
    35 import sun.security.krb5.KrbAsReqBuilder;
    35 import java.util.HashMap;
       
    36 import java.util.List;
       
    37 import java.util.Map;
       
    38 import java.util.Set;
       
    39 import javax.security.auth.kerberos.KerberosTicket;
       
    40 import javax.security.auth.Subject;
       
    41 
       
    42 import org.ietf.jgss.GSSName;
       
    43 
       
    44 import sun.security.jgss.GSSUtil;
    36 import sun.security.krb5.PrincipalName;
    45 import sun.security.krb5.PrincipalName;
    37 
    46 
    38 public class ReferralsTest {
    47 public class ReferralsTest {
    39     private static final boolean DEBUG = true;
    48     private static final boolean DEBUG = true;
    40     private static final String krbConfigName = "krb5-localkdc.conf";
    49     private static final String krbConfigName = "krb5-localkdc.conf";
    41     private static final String realmKDC1 = "RABBIT.HOLE";
    50     private static final String realmKDC1 = "RABBIT.HOLE";
    42     private static final String realmKDC2 = "DEV.RABBIT.HOLE";
    51     private static final String realmKDC2 = "DEV.RABBIT.HOLE";
    43     private static final char[] password = "123qwe@Z".toCharArray();
    52     private static final char[] password = "123qwe@Z".toCharArray();
       
    53 
       
    54     // Names
    44     private static final String clientName = "test";
    55     private static final String clientName = "test";
    45 
    56     private static final String serviceName = "http" +
       
    57             PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
       
    58             "server.dev.rabbit.hole";
       
    59 
       
    60     // Alias
    46     private static final String clientAlias = clientName +
    61     private static final String clientAlias = clientName +
    47             PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
    62             PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
    48 
    63 
    49     private static final String clientKDC1QueryName = clientAlias.replaceAll(
    64     // Names + realms
       
    65     private static final String clientKDC1Name = clientAlias.replaceAll(
    50             PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" +
    66             PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" +
    51             PrincipalName.NAME_REALM_SEPARATOR_STR) +
    67             PrincipalName.NAME_REALM_SEPARATOR_STR) +
    52             PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
    68             PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
    53     private static PrincipalName clientKDC1QueryPrincipal = null;
       
    54     static {
       
    55         try {
       
    56             clientKDC1QueryPrincipal = new PrincipalName(
       
    57                     clientKDC1QueryName, PrincipalName.KRB_NT_ENTERPRISE,
       
    58                     null);
       
    59         } catch (Throwable t) {}
       
    60     }
       
    61 
       
    62     private static final String clientKDC2Name = clientName +
    69     private static final String clientKDC2Name = clientName +
    63             PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
    70             PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
    64 
    71     private static final String serviceKDC2Name = serviceName +
    65     private static final String serviceName = "http" +
    72             PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
    66             PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
       
    67             "server.dev.rabbit.hole";
       
    68 
       
    69     private static Credentials tgt;
       
    70     private static Credentials tgs;
       
    71 
    73 
    72     public static void main(String[] args) throws Exception {
    74     public static void main(String[] args) throws Exception {
    73         try {
    75         try {
    74             initializeKDCs();
    76             initializeKDCs();
    75             getTGT();
    77             testSubjectCredentials();
    76             getTGS();
    78             testDelegated();
    77         } finally {
    79         } finally {
    78             cleanup();
    80             cleanup();
    79         }
    81         }
    80     }
    82     }
    81 
    83 
   106 
   108 
   107         kdc1.registerAlias(clientAlias, kdc2);
   109         kdc1.registerAlias(clientAlias, kdc2);
   108         kdc1.registerAlias(serviceName, kdc2);
   110         kdc1.registerAlias(serviceName, kdc2);
   109         kdc2.registerAlias(clientAlias, clientKDC2Name);
   111         kdc2.registerAlias(clientAlias, clientKDC2Name);
   110 
   112 
       
   113         Map<String,List<String>> mapKDC2 = new HashMap<>();
       
   114         mapKDC2.put(serviceName + "@" + realmKDC2, Arrays.asList(
       
   115                 new String[]{serviceName + "@" + realmKDC2}));
       
   116         kdc2.setOption(KDC.Option.ALLOW_S4U2PROXY, mapKDC2);
       
   117 
   111         KDC.saveConfig(krbConfigName, kdc1, kdc2,
   118         KDC.saveConfig(krbConfigName, kdc1, kdc2,
   112                     "forwardable=true");
   119                     "forwardable=true");
   113         System.setProperty("java.security.krb5.conf", krbConfigName);
   120         System.setProperty("java.security.krb5.conf", krbConfigName);
   114     }
   121     }
   115 
   122 
   118         if (f.exists()) {
   125         if (f.exists()) {
   119             f.delete();
   126             f.delete();
   120         }
   127         }
   121     }
   128     }
   122 
   129 
   123     private static void getTGT() throws Exception {
   130     /*
   124         KrbAsReqBuilder builder = new KrbAsReqBuilder(clientKDC1QueryPrincipal,
   131      * The client subject (whose principal is
   125                 password);
   132      * test@RABBIT.HOLE@RABBIT.HOLE) will obtain a TGT after
   126         tgt = builder.action().getCreds();
   133      * realm referral and name canonicalization (TGT cname
   127         builder.destroy();
   134      * will be test@DEV.RABBIT.HOLE). With this TGT, the client will request
       
   135      * a TGS for service http/server.dev.rabbit.hole@RABBIT.HOLE. After
       
   136      * realm referral, a http/server.dev.rabbit.hole@DEV.RABBIT.HOLE TGS
       
   137      * will be obtained.
       
   138      *
       
   139      * Assert that we get the proper TGT and TGS tickets, and that they are
       
   140      * associated to the client subject.
       
   141      *
       
   142      * Assert that if we request a TGS for the same service again (based on the
       
   143      * original service name), we don't get a new one but the previous,
       
   144      * already in the subject credentials.
       
   145      */
       
   146     private static void testSubjectCredentials() throws Exception {
       
   147         Subject clientSubject = new Subject();
       
   148         Context clientContext = Context.fromUserPass(clientSubject,
       
   149                 clientKDC1Name, password, false);
       
   150 
       
   151         Set<Principal> clientPrincipals = clientSubject.getPrincipals();
       
   152         if (clientPrincipals.size() != 1) {
       
   153             throw new Exception("Only one client subject principal expected");
       
   154         }
       
   155         Principal clientPrincipal = clientPrincipals.iterator().next();
   128         if (DEBUG) {
   156         if (DEBUG) {
   129             System.out.println("TGT");
   157             System.out.println("Client subject principal: " +
   130             System.out.println("----------------------");
   158                     clientPrincipal.getName());
   131             System.out.println(tgt);
   159         }
   132             System.out.println("----------------------");
   160         if (!clientPrincipal.getName().equals(clientKDC1Name)) {
   133         }
   161             throw new Exception("Unexpected client subject principal.");
   134         if (tgt == null) {
   162         }
   135             throw new Exception("TGT is null");
   163 
   136         }
   164         clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
   137         if (!tgt.getClient().getName().equals(clientKDC2Name)) {
   165         clientContext.take(new byte[0]);
   138             throw new Exception("Unexpected TGT client");
   166         Set<KerberosTicket> clientTickets =
   139         }
   167                 clientSubject.getPrivateCredentials(KerberosTicket.class);
   140         String[] tgtServerNames = tgt.getServer().getNameStrings();
   168         boolean tgtFound = false;
   141         if (tgtServerNames.length != 2 || !tgtServerNames[0].equals(
   169         boolean tgsFound = false;
   142                 PrincipalName.TGS_DEFAULT_SRV_NAME) ||
   170         for (KerberosTicket clientTicket : clientTickets) {
   143                 !tgtServerNames[1].equals(realmKDC2) ||
   171             String cname = clientTicket.getClient().getName();
   144                 !tgt.getServer().getRealmString().equals(realmKDC2)) {
   172             String sname = clientTicket.getServer().getName();
   145             throw new Exception("Unexpected TGT server");
   173             if (cname.equals(clientKDC2Name)) {
   146         }
   174                 if (sname.equals(PrincipalName.TGS_DEFAULT_SRV_NAME +
   147     }
   175                         PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
   148 
   176                         realmKDC2 + PrincipalName.NAME_REALM_SEPARATOR_STR +
   149     private static void getTGS() throws Exception {
   177                         realmKDC2)) {
   150         tgs = CredentialsUtil.acquireServiceCreds(serviceName +
   178                     tgtFound = true;
   151                 PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1, tgt);
   179                 } else if (sname.equals(serviceKDC2Name)) {
       
   180                     tgsFound = true;
       
   181                 }
       
   182             }
       
   183             if (DEBUG) {
       
   184                 System.out.println("Client subject KerberosTicket:");
       
   185                 System.out.println(clientTicket);
       
   186             }
       
   187         }
       
   188         if (!tgtFound || !tgsFound) {
       
   189             throw new Exception("client subject tickets (TGT/TGS) not found.");
       
   190         }
       
   191         int numOfTickets = clientTickets.size();
       
   192         clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
       
   193         clientContext.take(new byte[0]);
       
   194         clientContext.status();
       
   195         int newNumOfTickets =
       
   196                 clientSubject.getPrivateCredentials(KerberosTicket.class).size();
   152         if (DEBUG) {
   197         if (DEBUG) {
   153             System.out.println("TGS");
   198             System.out.println("client subject number of tickets: " +
   154             System.out.println("----------------------");
   199                     numOfTickets);
   155             System.out.println(tgs);
   200             System.out.println("client subject new number of tickets: " +
   156             System.out.println("----------------------");
   201                     newNumOfTickets);
   157         }
   202         }
   158         if (tgs == null) {
   203         if (numOfTickets != newNumOfTickets) {
   159             throw new Exception("TGS is null");
   204             throw new Exception("Useless client subject TGS request because" +
   160         }
   205                     " TGS was not found in private credentials.");
   161         if (!tgs.getClient().getName().equals(clientKDC2Name)) {
   206         }
   162             throw new Exception("Unexpected TGS client");
   207     }
   163         }
   208 
   164         if (!tgs.getServer().getNameString().equals(serviceName) ||
   209     /*
   165                 !tgs.getServer().getRealmString().equals(realmKDC2)) {
   210      * The server (http/server.dev.rabbit.hole@DEV.RABBIT.HOLE)
   166             throw new Exception("Unexpected TGS server");
   211      * will authenticate on itself on behalf of the client
       
   212      * (test@DEV.RABBIT.HOLE). Cross-realm referrals will occur
       
   213      * when requesting different TGTs and TGSs (including the
       
   214      * request for delegated credentials).
       
   215      */
       
   216     private static void testDelegated() throws Exception {
       
   217         Context c = Context.fromUserPass(clientKDC2Name,
       
   218                 password, false);
       
   219         c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
       
   220         Context s = Context.fromUserPass(serviceKDC2Name,
       
   221                 password, true);
       
   222         s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
       
   223         Context.handshake(c, s);
       
   224         Context delegatedContext = s.delegated();
       
   225         delegatedContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
       
   226         delegatedContext.x().requestMutualAuth(false);
       
   227         Context s2 = Context.fromUserPass(serviceKDC2Name,
       
   228                 password, true);
       
   229         s2.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
       
   230 
       
   231         // Test authentication
       
   232         Context.handshake(delegatedContext, s2);
       
   233         if (!delegatedContext.x().isEstablished() || !s2.x().isEstablished()) {
       
   234             throw new Exception("Delegated authentication failed");
       
   235         }
       
   236 
       
   237         // Test identities
       
   238         GSSName contextInitiatorName = delegatedContext.x().getSrcName();
       
   239         GSSName contextAcceptorName = delegatedContext.x().getTargName();
       
   240         if (DEBUG) {
       
   241             System.out.println("Context initiator: " + contextInitiatorName);
       
   242             System.out.println("Context acceptor: " + contextAcceptorName);
       
   243         }
       
   244         if (!contextInitiatorName.toString().equals(clientKDC2Name) ||
       
   245                 !contextAcceptorName.toString().equals(serviceName)) {
       
   246             throw new Exception("Unexpected initiator or acceptor names");
   167         }
   247         }
   168     }
   248     }
   169 }
   249 }