src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java
changeset 55258 d65d3c37232c
parent 47216 71c04702a3d5
child 57487 643978a35f6e
equal deleted inserted replaced
55257:442b86eb633c 55258:d65d3c37232c
     1 /*
     1 /*
     2  * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    31 
    31 
    32 package sun.security.krb5.internal;
    32 package sun.security.krb5.internal;
    33 
    33 
    34 import sun.security.krb5.*;
    34 import sun.security.krb5.*;
    35 import java.io.IOException;
    35 import java.io.IOException;
       
    36 import java.util.LinkedList;
       
    37 import java.util.List;
    36 
    38 
    37 /**
    39 /**
    38  * This class is a utility that contains much of the TGS-Exchange
    40  * This class is a utility that contains much of the TGS-Exchange
    39  * protocol. It is used by ../Credentials.java for service ticket
    41  * protocol. It is used by ../Credentials.java for service ticket
    40  * acquisition in both the normal and the x-realm case.
    42  * acquisition in both the normal and the x-realm case.
    59             throw new KrbException("Cross realm impersonation not supported");
    61             throw new KrbException("Cross realm impersonation not supported");
    60         }
    62         }
    61         if (!ccreds.isForwardable()) {
    63         if (!ccreds.isForwardable()) {
    62             throw new KrbException("S4U2self needs a FORWARDABLE ticket");
    64             throw new KrbException("S4U2self needs a FORWARDABLE ticket");
    63         }
    65         }
    64         KrbTgsReq req = new KrbTgsReq(
    66         Credentials creds = serviceCreds(KDCOptions.with(KDCOptions.FORWARDABLE),
    65                 ccreds,
    67                 ccreds, ccreds.getClient(), ccreds.getClient(), null,
    66                 ccreds.getClient(),
    68                 new PAData[] {new PAData(Krb5.PA_FOR_USER,
    67                 new PAData(Krb5.PA_FOR_USER,
    69                         new PAForUserEnc(client,
    68                     new PAForUserEnc(client,
    70                             ccreds.getSessionKey()).asn1Encode())});
    69                         ccreds.getSessionKey()).asn1Encode()));
       
    70         Credentials creds = req.sendAndGetCreds();
       
    71         if (!creds.getClient().equals(client)) {
    71         if (!creds.getClient().equals(client)) {
    72             throw new KrbException("S4U2self request not honored by KDC");
    72             throw new KrbException("S4U2self request not honored by KDC");
    73         }
    73         }
    74         if (!creds.isForwardable()) {
    74         if (!creds.isForwardable()) {
    75             throw new KrbException("S4U2self ticket must be FORWARDABLE");
    75             throw new KrbException("S4U2self ticket must be FORWARDABLE");
    87      */
    87      */
    88     public static Credentials acquireS4U2proxyCreds(
    88     public static Credentials acquireS4U2proxyCreds(
    89                 String backend, Ticket second,
    89                 String backend, Ticket second,
    90                 PrincipalName client, Credentials ccreds)
    90                 PrincipalName client, Credentials ccreds)
    91             throws KrbException, IOException {
    91             throws KrbException, IOException {
    92         KrbTgsReq req = new KrbTgsReq(
    92         Credentials creds = serviceCreds(KDCOptions.with(
    93                 ccreds,
    93                 KDCOptions.CNAME_IN_ADDL_TKT, KDCOptions.FORWARDABLE),
    94                 second,
    94                 ccreds, ccreds.getClient(), new PrincipalName(backend),
    95                 new PrincipalName(backend));
    95                 new Ticket[] {second}, null);
    96         Credentials creds = req.sendAndGetCreds();
       
    97         if (!creds.getClient().equals(client)) {
    96         if (!creds.getClient().equals(client)) {
    98             throw new KrbException("S4U2proxy request not honored by KDC");
    97             throw new KrbException("S4U2proxy request not honored by KDC");
    99         }
    98         }
   100         return creds;
    99         return creds;
   101     }
   100     }
   112      * @param ccreds client's initial credential
   111      * @param ccreds client's initial credential
   113      */
   112      */
   114     public static Credentials acquireServiceCreds(
   113     public static Credentials acquireServiceCreds(
   115                 String service, Credentials ccreds)
   114                 String service, Credentials ccreds)
   116             throws KrbException, IOException {
   115             throws KrbException, IOException {
   117         PrincipalName sname = new PrincipalName(service);
   116         PrincipalName sname = new PrincipalName(service,
   118         String serviceRealm = sname.getRealmString();
   117                 PrincipalName.KRB_NT_SRV_HST);
   119         String localRealm = ccreds.getClient().getRealmString();
   118         return serviceCreds(sname, ccreds);
   120 
       
   121         if (localRealm.equals(serviceRealm)) {
       
   122             if (DEBUG) {
       
   123                 System.out.println(
       
   124                         ">>> Credentials acquireServiceCreds: same realm");
       
   125             }
       
   126             return serviceCreds(sname, ccreds);
       
   127         }
       
   128         Credentials theCreds = null;
       
   129 
       
   130         boolean[] okAsDelegate = new boolean[1];
       
   131         Credentials theTgt = getTGTforRealm(localRealm, serviceRealm,
       
   132                 ccreds, okAsDelegate);
       
   133         if (theTgt != null) {
       
   134             if (DEBUG) {
       
   135                 System.out.println(">>> Credentials acquireServiceCreds: "
       
   136                         + "got right tgt");
       
   137                 System.out.println(">>> Credentials acquireServiceCreds: "
       
   138                         + "obtaining service creds for " + sname);
       
   139             }
       
   140 
       
   141             try {
       
   142                 theCreds = serviceCreds(sname, theTgt);
       
   143             } catch (Exception exc) {
       
   144                 if (DEBUG) {
       
   145                     System.out.println(exc);
       
   146                 }
       
   147                 theCreds = null;
       
   148             }
       
   149         }
       
   150 
       
   151         if (theCreds != null) {
       
   152             if (DEBUG) {
       
   153                 System.out.println(">>> Credentials acquireServiceCreds: "
       
   154                         + "returning creds:");
       
   155                 Credentials.printDebug(theCreds);
       
   156             }
       
   157             if (!okAsDelegate[0]) {
       
   158                 theCreds.resetDelegate();
       
   159             }
       
   160             return theCreds;
       
   161         }
       
   162         throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED,
       
   163                                     "No service creds");
       
   164     }
   119     }
   165 
   120 
   166     /**
   121     /**
   167      * Gets a TGT to another realm
   122      * Gets a TGT to another realm
   168      * @param localRealm this realm
   123      * @param localRealm this realm
   303     * This method does the real job to request the service credential.
   258     * This method does the real job to request the service credential.
   304     */
   259     */
   305     private static Credentials serviceCreds(
   260     private static Credentials serviceCreds(
   306             PrincipalName service, Credentials ccreds)
   261             PrincipalName service, Credentials ccreds)
   307             throws KrbException, IOException {
   262             throws KrbException, IOException {
   308         return new KrbTgsReq(ccreds, service).sendAndGetCreds();
   263         return serviceCreds(new KDCOptions(), ccreds,
       
   264                 ccreds.getClient(), service, null, null);
       
   265     }
       
   266 
       
   267     /*
       
   268      * Obtains credentials for a service (TGS).
       
   269      * Cross-realm referrals are handled if enabled. A fallback scheme
       
   270      * without cross-realm referrals supports is used in case of server
       
   271      * error to maintain backward compatibility.
       
   272      */
       
   273     private static Credentials serviceCreds(
       
   274             KDCOptions options, Credentials asCreds,
       
   275             PrincipalName cname, PrincipalName sname,
       
   276             Ticket[] additionalTickets, PAData[] extraPAs)
       
   277             throws KrbException, IOException {
       
   278         if (!Config.DISABLE_REFERRALS) {
       
   279             try {
       
   280                 return serviceCredsReferrals(options, asCreds,
       
   281                         cname, sname, additionalTickets, extraPAs);
       
   282             } catch (KrbException e) {
       
   283                 // Server may raise an error if CANONICALIZE is true.
       
   284                 // Try CANONICALIZE false.
       
   285             }
       
   286         }
       
   287         return serviceCredsSingle(options, asCreds,
       
   288                 cname, sname, additionalTickets, extraPAs);
       
   289     }
       
   290 
       
   291     /*
       
   292      * Obtains credentials for a service (TGS).
       
   293      * May handle and follow cross-realm referrals as defined by RFC 6806.
       
   294      */
       
   295     private static Credentials serviceCredsReferrals(
       
   296             KDCOptions options, Credentials asCreds,
       
   297             PrincipalName cname, PrincipalName sname,
       
   298             Ticket[] additionalTickets, PAData[] extraPAs)
       
   299             throws KrbException, IOException {
       
   300         options = new KDCOptions(options.toBooleanArray());
       
   301         options.set(KDCOptions.CANONICALIZE, true);
       
   302         PrincipalName cSname = sname;
       
   303         Credentials creds = null;
       
   304         boolean isReferral = false;
       
   305         List<String> referrals = new LinkedList<>();
       
   306         while (referrals.size() <= Config.MAX_REFERRALS) {
       
   307             ReferralsCache.ReferralCacheEntry ref =
       
   308                     ReferralsCache.get(sname, cSname.getRealmString());
       
   309             String toRealm = null;
       
   310             if (ref == null) {
       
   311                 creds = serviceCredsSingle(options, asCreds,
       
   312                         cname, cSname, additionalTickets, extraPAs);
       
   313                 PrincipalName server = creds.getServer();
       
   314                 if (!cSname.equals(server)) {
       
   315                     String[] serverNameStrings = server.getNameStrings();
       
   316                     if (serverNameStrings.length == 2 &&
       
   317                         serverNameStrings[0].equals(
       
   318                                 PrincipalName.TGS_DEFAULT_SRV_NAME) &&
       
   319                         !cSname.getRealmAsString().equals(serverNameStrings[1])) {
       
   320                         // Server Name (sname) has the following format:
       
   321                         //      krbtgt/TO-REALM.COM@FROM-REALM.COM
       
   322                         ReferralsCache.put(sname, server.getRealmString(),
       
   323                                 serverNameStrings[1], creds);
       
   324                         toRealm = serverNameStrings[1];
       
   325                         isReferral = true;
       
   326                         asCreds = creds;
       
   327                     }
       
   328                 }
       
   329             } else {
       
   330                 toRealm = ref.getToRealm();
       
   331                 asCreds = ref.getCreds();
       
   332                 isReferral = true;
       
   333             }
       
   334             if (isReferral) {
       
   335                 if (referrals.contains(toRealm)) {
       
   336                     // Referrals loop detected
       
   337                     return null;
       
   338                 }
       
   339                 cSname = new PrincipalName(cSname.getNameString(),
       
   340                         cSname.getNameType(), toRealm);
       
   341                 referrals.add(toRealm);
       
   342                 isReferral = false;
       
   343                 continue;
       
   344             }
       
   345             break;
       
   346         }
       
   347         return creds;
       
   348     }
       
   349 
       
   350     /*
       
   351      * Obtains credentials for a service (TGS).
       
   352      * If the service realm is different than the one in the TGT, a new TGT for
       
   353      * the service realm is obtained first (see getTGTforRealm call). This is
       
   354      * not expected when following cross-realm referrals because the referral
       
   355      * TGT realm matches the service realm.
       
   356      */
       
   357     private static Credentials serviceCredsSingle(
       
   358             KDCOptions options, Credentials asCreds,
       
   359             PrincipalName cname, PrincipalName sname,
       
   360             Ticket[] additionalTickets, PAData[] extraPAs)
       
   361             throws KrbException, IOException {
       
   362         Credentials theCreds = null;
       
   363         boolean[] okAsDelegate = new boolean[]{true};
       
   364         String[] serverAsCredsNames = asCreds.getServer().getNameStrings();
       
   365         String tgtRealm = serverAsCredsNames[1];
       
   366         String serviceRealm = sname.getRealmString();
       
   367         if (!serviceRealm.equals(tgtRealm)) {
       
   368             // This is a cross-realm service request
       
   369             if (DEBUG) {
       
   370                 System.out.println(">>> serviceCredsSingle:" +
       
   371                         " cross-realm authentication");
       
   372                 System.out.println(">>> serviceCredsSingle:" +
       
   373                         " obtaining credentials from " + tgtRealm +
       
   374                         " to " + serviceRealm);
       
   375             }
       
   376             Credentials newTgt = getTGTforRealm(tgtRealm, serviceRealm,
       
   377                     asCreds, okAsDelegate);
       
   378             if (newTgt == null) {
       
   379                 throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED,
       
   380                         "No service creds");
       
   381             }
       
   382             if (DEBUG) {
       
   383                 System.out.println(">>> Cross-realm TGT Credentials" +
       
   384                         " serviceCredsSingle: ");
       
   385                 Credentials.printDebug(newTgt);
       
   386             }
       
   387             asCreds = newTgt;
       
   388             cname = asCreds.getClient();
       
   389         } else if (DEBUG) {
       
   390             System.out.println(">>> Credentials serviceCredsSingle:" +
       
   391                     " same realm");
       
   392         }
       
   393         KrbTgsReq req = new KrbTgsReq(options, asCreds,
       
   394                 cname, sname, additionalTickets, extraPAs);
       
   395         theCreds = req.sendAndGetCreds();
       
   396         if (theCreds != null) {
       
   397             if (DEBUG) {
       
   398                 System.out.println(">>> TGS credentials serviceCredsSingle:");
       
   399                 Credentials.printDebug(theCreds);
       
   400             }
       
   401             if (!okAsDelegate[0]) {
       
   402                 theCreds.resetDelegate();
       
   403             }
       
   404         }
       
   405         return theCreds;
   309     }
   406     }
   310 }
   407 }