1 /*
2  * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
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
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  *
28  *  (C) Copyright IBM Corp. 1999 All Rights Reserved.
29  *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
30  */
31 
32 package sun.security.krb5;
33 
34 import sun.security.action.GetPropertyAction;
35 import sun.security.krb5.internal.*;
36 import sun.security.krb5.internal.ccache.CredentialsCache;
37 import sun.security.krb5.internal.crypto.EType;
38 import java.io.IOException;
39 import java.util.Date;
40 import java.util.Locale;
41 import java.net.InetAddress;
42 
43 /**
44  * This class encapsulates the concept of a Kerberos service
45  * credential. That includes a Kerberos ticket and an associated
46  * session key.
47  */
48 public class Credentials {
49 
50     Ticket ticket;
51     PrincipalName client;
52     PrincipalName clientAlias;
53     PrincipalName server;
54     PrincipalName serverAlias;
55     EncryptionKey key;
56     TicketFlags flags;
57     KerberosTime authTime;
58     KerberosTime startTime;
59     KerberosTime endTime;
60     KerberosTime renewTill;
61     HostAddresses cAddr;
62     AuthorizationData authzData;
63     private static boolean DEBUG = Krb5.DEBUG;
64     private static CredentialsCache cache;
65     static boolean alreadyLoaded = false;
66     private static boolean alreadyTried = false;
67 
68     private Credentials proxy = null;
69 
getProxy()70     public Credentials getProxy() {
71         return proxy;
72     }
73 
setProxy(Credentials proxy)74     public Credentials setProxy(Credentials proxy) {
75         this.proxy = proxy;
76         return this;
77     }
78 
79     // Read native ticket with session key type in the given list
acquireDefaultNativeCreds(int[] eTypes)80     private static native Credentials acquireDefaultNativeCreds(int[] eTypes);
81 
Credentials(Ticket new_ticket, PrincipalName new_client, PrincipalName new_client_alias, PrincipalName new_server, PrincipalName new_server_alias, EncryptionKey new_key, TicketFlags new_flags, KerberosTime authTime, KerberosTime new_startTime, KerberosTime new_endTime, KerberosTime renewTill, HostAddresses cAddr, AuthorizationData authzData)82     public Credentials(Ticket new_ticket,
83                        PrincipalName new_client,
84                        PrincipalName new_client_alias,
85                        PrincipalName new_server,
86                        PrincipalName new_server_alias,
87                        EncryptionKey new_key,
88                        TicketFlags new_flags,
89                        KerberosTime authTime,
90                        KerberosTime new_startTime,
91                        KerberosTime new_endTime,
92                        KerberosTime renewTill,
93                        HostAddresses cAddr,
94                        AuthorizationData authzData) {
95         this(new_ticket, new_client, new_client_alias, new_server,
96                 new_server_alias, new_key, new_flags, authTime,
97                 new_startTime, new_endTime, renewTill, cAddr);
98         this.authzData = authzData;
99     }
100 
Credentials(Ticket new_ticket, PrincipalName new_client, PrincipalName new_client_alias, PrincipalName new_server, PrincipalName new_server_alias, EncryptionKey new_key, TicketFlags new_flags, KerberosTime authTime, KerberosTime new_startTime, KerberosTime new_endTime, KerberosTime renewTill, HostAddresses cAddr)101     public Credentials(Ticket new_ticket,
102                        PrincipalName new_client,
103                        PrincipalName new_client_alias,
104                        PrincipalName new_server,
105                        PrincipalName new_server_alias,
106                        EncryptionKey new_key,
107                        TicketFlags new_flags,
108                        KerberosTime authTime,
109                        KerberosTime new_startTime,
110                        KerberosTime new_endTime,
111                        KerberosTime renewTill,
112                        HostAddresses cAddr) {
113         ticket = new_ticket;
114         client = new_client;
115         clientAlias = new_client_alias;
116         server = new_server;
117         serverAlias = new_server_alias;
118         key = new_key;
119         flags = new_flags;
120         this.authTime = authTime;
121         startTime = new_startTime;
122         endTime = new_endTime;
123         this.renewTill = renewTill;
124         this.cAddr = cAddr;
125     }
126 
Credentials(byte[] encoding, String client, String clientAlias, String server, String serverAlias, byte[] keyBytes, int keyType, boolean[] flags, Date authTime, Date startTime, Date endTime, Date renewTill, InetAddress[] cAddrs)127     public Credentials(byte[] encoding,
128                        String client,
129                        String clientAlias,
130                        String server,
131                        String serverAlias,
132                        byte[] keyBytes,
133                        int keyType,
134                        boolean[] flags,
135                        Date authTime,
136                        Date startTime,
137                        Date endTime,
138                        Date renewTill,
139                        InetAddress[] cAddrs) throws KrbException, IOException {
140         this(new Ticket(encoding),
141              new PrincipalName(client, PrincipalName.KRB_NT_PRINCIPAL),
142              (clientAlias == null? null : new PrincipalName(clientAlias,
143                      PrincipalName.KRB_NT_PRINCIPAL)),
144              new PrincipalName(server, PrincipalName.KRB_NT_SRV_INST),
145              (serverAlias == null? null : new PrincipalName(serverAlias,
146                      PrincipalName.KRB_NT_SRV_INST)),
147              new EncryptionKey(keyType, keyBytes),
148              (flags == null? null: new TicketFlags(flags)),
149              (authTime == null? null: new KerberosTime(authTime)),
150              (startTime == null? null: new KerberosTime(startTime)),
151              (endTime == null? null: new KerberosTime(endTime)),
152              (renewTill == null? null: new KerberosTime(renewTill)),
153              null); // caddrs are in the encoding at this point
154     }
155 
156     /**
157      * Acquires a service ticket for the specified service
158      * principal. If the service ticket is not already available, it
159      * obtains a new one from the KDC.
160      */
161     /*
162     public Credentials(Credentials tgt, PrincipalName service)
163         throws KrbException {
164     }
165     */
166 
getClient()167     public final PrincipalName getClient() {
168         return client;
169     }
170 
getClientAlias()171     public final PrincipalName getClientAlias() {
172         return clientAlias;
173     }
174 
getServer()175     public final PrincipalName getServer() {
176         return server;
177     }
178 
getServerAlias()179     public final PrincipalName getServerAlias() {
180         return serverAlias;
181     }
182 
getSessionKey()183     public final EncryptionKey getSessionKey() {
184         return key;
185     }
186 
getAuthTime()187     public final Date getAuthTime() {
188         if (authTime != null) {
189             return authTime.toDate();
190         } else {
191             return null;
192         }
193     }
194 
getStartTime()195     public final Date getStartTime() {
196         if (startTime != null)
197             {
198                 return startTime.toDate();
199             }
200         return null;
201     }
202 
getEndTime()203     public final Date getEndTime() {
204         if (endTime != null)
205             {
206                 return endTime.toDate();
207             }
208         return null;
209     }
210 
getRenewTill()211     public final Date getRenewTill() {
212         if (renewTill != null)
213             {
214                 return renewTill.toDate();
215             }
216         return null;
217     }
218 
getFlags()219     public final boolean[] getFlags() {
220         if (flags == null) // Can be in a KRB-CRED
221         return null;
222         return flags.toBooleanArray();
223     }
224 
getClientAddresses()225     public final InetAddress[] getClientAddresses() {
226 
227         if (cAddr == null)
228         return null;
229 
230         return cAddr.getInetAddresses();
231     }
232 
getEncoded()233     public final byte[] getEncoded() {
234         byte[] retVal = null;
235         try {
236             retVal = ticket.asn1Encode();
237         } catch (Asn1Exception e) {
238             if (DEBUG)
239             System.out.println(e);
240         } catch (IOException ioe) {
241             if (DEBUG)
242             System.out.println(ioe);
243         }
244         return retVal;
245     }
246 
isForwardable()247     public boolean isForwardable() {
248         return flags.get(Krb5.TKT_OPTS_FORWARDABLE);
249     }
250 
isRenewable()251     public boolean isRenewable() {
252         return flags.get(Krb5.TKT_OPTS_RENEWABLE);
253     }
254 
getTicket()255     public Ticket getTicket() {
256         return ticket;
257     }
258 
getTicketFlags()259     public TicketFlags getTicketFlags() {
260         return flags;
261     }
262 
getAuthzData()263     public AuthorizationData getAuthzData() {
264         return authzData;
265     }
266     /**
267      * Checks if the service ticket returned by the KDC has the OK-AS-DELEGATE
268      * flag set
269      * @return true if OK-AS_DELEGATE flag is set, otherwise, return false.
270      */
checkDelegate()271     public boolean checkDelegate() {
272         return flags.get(Krb5.TKT_OPTS_DELEGATE);
273     }
274 
275     /**
276      * Reset TKT_OPTS_DELEGATE to false, called at credentials acquirement
277      * when one of the cross-realm TGTs does not have the OK-AS-DELEGATE
278      * flag set. This info must be preservable and restorable through
279      * the Krb5Util.credsToTicket/ticketToCreds() methods so that even if
280      * the service ticket is cached it still remembers the cross-realm
281      * authentication result.
282      */
resetDelegate()283     public void resetDelegate() {
284         flags.set(Krb5.TKT_OPTS_DELEGATE, false);
285     }
286 
renew()287     public Credentials renew() throws KrbException, IOException {
288         KDCOptions options = new KDCOptions();
289         options.set(KDCOptions.RENEW, true);
290         /*
291          * Added here to pass KrbKdcRep.check:73
292          */
293         options.set(KDCOptions.RENEWABLE, true);
294 
295         return new KrbTgsReq(options,
296                              this,
297                              server,
298                              serverAlias,
299                              null, // from
300                              null, // till
301                              null, // rtime
302                              null, // eTypes
303                              cAddr,
304                              null,
305                              null,
306                              null).sendAndGetCreds();
307     }
308 
309     /**
310      * Returns a TGT for the given client principal from a ticket cache.
311      *
312      * @param princ the client principal. A value of null means that the
313      * default principal name in the credentials cache will be used.
314      * @param ticketCache the path to the tickets file. A value
315      * of null will be accepted to indicate that the default
316      * path should be searched
317      * @return the TGT credentials or null if none were found. If the tgt
318      * expired, it is the responsibility of the caller to determine this.
319      */
acquireTGTFromCache(PrincipalName princ, String ticketCache)320     public static Credentials acquireTGTFromCache(PrincipalName princ,
321                                                   String ticketCache)
322         throws KrbException, IOException {
323 
324         if (ticketCache == null) {
325             // The default ticket cache on Windows and Mac is not a file.
326             String os = GetPropertyAction.privilegedGetProperty("os.name");
327             if (os.toUpperCase(Locale.ENGLISH).startsWith("WINDOWS") ||
328                     os.toUpperCase(Locale.ENGLISH).contains("OS X")) {
329                 Credentials creds = acquireDefaultCreds();
330                 if (creds == null) {
331                     if (DEBUG) {
332                         System.out.println(">>> Found no TGT's in LSA");
333                     }
334                     return null;
335                 }
336                 if (princ != null) {
337                     if (creds.getClient().equals(princ)) {
338                         if (DEBUG) {
339                             System.out.println(">>> Obtained TGT from LSA: "
340                                                + creds);
341                         }
342                         return creds;
343                     } else {
344                         if (DEBUG) {
345                             System.out.println(">>> LSA contains TGT for "
346                                                + creds.getClient()
347                                                + " not "
348                                                + princ);
349                         }
350                         return null;
351                     }
352                 } else {
353                     if (DEBUG) {
354                         System.out.println(">>> Obtained TGT from LSA: "
355                                            + creds);
356                     }
357                     return creds;
358                 }
359             }
360         }
361 
362         /*
363          * Returns the appropriate cache. If ticketCache is null, it is the
364          * default cache otherwise it is the cache filename contained in it.
365          */
366         CredentialsCache ccache =
367             CredentialsCache.getInstance(princ, ticketCache);
368 
369         if (ccache == null) {
370             return null;
371         }
372 
373         Credentials tgtCred = ccache.getInitialCreds();
374 
375         if (tgtCred == null) {
376             return null;
377         }
378 
379         if (EType.isSupported(tgtCred.key.getEType())) {
380             return tgtCred;
381         } else {
382             if (DEBUG) {
383                 System.out.println(
384                     ">>> unsupported key type found the default TGT: " +
385                     tgtCred.key.getEType());
386             }
387             return null;
388         }
389     }
390 
391     /**
392      * Acquires default credentials.
393      * <br>The possible locations for default credentials cache is searched in
394      * the following order:
395      * <ol>
396      * <li> The directory and cache file name specified by "KRB5CCNAME" system.
397      * property.
398      * <li> The directory and cache file name specified by "KRB5CCNAME"
399      * environment variable.
400      * <li> A cache file named krb5cc_{user.name} at {user.home} directory.
401      * </ol>
402      * @return a <code>KrbCreds</code> object if the credential is found,
403      * otherwise return null.
404      */
405 
406     // this method is intentionally changed to not check if the caller's
407     // principal name matches cache file's principal name.
408     // It assumes that the GSS call has
409     // the privilege to access the default cache file.
410 
411     // This method is only called on Windows and Mac OS X, the native
412     // acquireDefaultNativeCreds is also available on these platforms.
acquireDefaultCreds()413     public static synchronized Credentials acquireDefaultCreds() {
414         Credentials result = null;
415 
416         if (cache == null) {
417             cache = CredentialsCache.getInstance();
418         }
419         if (cache != null) {
420             Credentials temp = cache.getInitialCreds();
421             if (temp != null) {
422                 if (DEBUG) {
423                     System.out.println(">>> KrbCreds found the default ticket"
424                             + " granting ticket in credential cache.");
425                 }
426                 if (EType.isSupported(temp.key.getEType())) {
427                     result = temp;
428                 } else {
429                     if (DEBUG) {
430                         System.out.println(
431                             ">>> unsupported key type found the default TGT: " +
432                             temp.key.getEType());
433                     }
434                 }
435             }
436         }
437         if (result == null) {
438             // Doesn't seem to be a default cache on this system or
439             // TGT has unsupported encryption type
440 
441             if (!alreadyTried) {
442                 // See if there's any native code to load
443                 try {
444                     ensureLoaded();
445                 } catch (Exception e) {
446                     if (DEBUG) {
447                         System.out.println("Can not load credentials cache");
448                         e.printStackTrace();
449                     }
450                     alreadyTried = true;
451                 }
452             }
453             if (alreadyLoaded) {
454                 // There is some native code
455                 if (DEBUG) {
456                     System.out.println(">> Acquire default native Credentials");
457                 }
458                 try {
459                     result = acquireDefaultNativeCreds(
460                             EType.getDefaults("default_tkt_enctypes"));
461                 } catch (KrbException ke) {
462                     // when there is no default_tkt_enctypes.
463                 }
464             }
465         }
466         return result;
467     }
468 
469     /**
470      * Acquires credentials for a specified service using initial credential.
471      * When the service has a different realm
472      * from the initial credential, we do cross-realm authentication
473      * - first, we use the current credential to get
474      * a cross-realm credential from the local KDC, then use that
475      * cross-realm credential to request service credential
476      * from the foreigh KDC.
477      *
478      * @param service the name of service principal using format
479      * components@realm
480      * @param ccreds client's initial credential.
481      * @exception IOException if an error occurs in reading the credentials
482      * cache
483      * @exception KrbException if an error occurs specific to Kerberos
484      * @return a <code>Credentials</code> object.
485      */
486 
acquireServiceCreds(String service, Credentials ccreds)487     public static Credentials acquireServiceCreds(String service,
488                                                   Credentials ccreds)
489         throws KrbException, IOException {
490         return CredentialsUtil.acquireServiceCreds(service, ccreds);
491     }
492 
acquireS4U2selfCreds(PrincipalName user, Credentials ccreds)493     public static Credentials acquireS4U2selfCreds(PrincipalName user,
494             Credentials ccreds) throws KrbException, IOException {
495         return CredentialsUtil.acquireS4U2selfCreds(user, ccreds);
496     }
497 
acquireS4U2proxyCreds(String service, Ticket second, PrincipalName client, Credentials ccreds)498     public static Credentials acquireS4U2proxyCreds(String service,
499             Ticket second, PrincipalName client, Credentials ccreds)
500         throws KrbException, IOException {
501         return CredentialsUtil.acquireS4U2proxyCreds(
502                 service, second, client, ccreds);
503     }
504 
getCache()505     public CredentialsCache getCache() {
506         return cache;
507     }
508 
509     /*
510      * Prints out debug info.
511      */
printDebug(Credentials c)512     public static void printDebug(Credentials c) {
513         System.out.println(">>> DEBUG: ----Credentials----");
514         System.out.println("\tclient: " + c.client.toString());
515         if (c.clientAlias != null)
516             System.out.println("\tclient alias: " + c.clientAlias.toString());
517         System.out.println("\tserver: " + c.server.toString());
518         if (c.serverAlias != null)
519             System.out.println("\tserver alias: " + c.serverAlias.toString());
520         System.out.println("\tticket: sname: " + c.ticket.sname.toString());
521         if (c.startTime != null) {
522             System.out.println("\tstartTime: " + c.startTime.getTime());
523         }
524         System.out.println("\tendTime: " + c.endTime.getTime());
525         System.out.println("        ----Credentials end----");
526     }
527 
528 
ensureLoaded()529     static void ensureLoaded() {
530         java.security.AccessController.doPrivileged(
531                 new java.security.PrivilegedAction<Void> () {
532                         public Void run() {
533                                 if (System.getProperty("os.name").contains("OS X")) {
534                                     System.loadLibrary("osxkrb5");
535                                 } else {
536                                     System.loadLibrary("w2k_lsa_auth");
537                                 }
538                                 return null;
539                         }
540                 });
541         alreadyLoaded = true;
542     }
543 
toString()544     public String toString() {
545         StringBuilder sb = new StringBuilder("Credentials:");
546         sb.append(    "\n      client=").append(client);
547         if (clientAlias != null)
548             sb.append(    "\n      clientAlias=").append(clientAlias);
549         sb.append(    "\n      server=").append(server);
550         if (serverAlias != null)
551             sb.append(    "\n      serverAlias=").append(serverAlias);
552         if (authTime != null) {
553             sb.append("\n    authTime=").append(authTime);
554         }
555         if (startTime != null) {
556             sb.append("\n   startTime=").append(startTime);
557         }
558         sb.append(    "\n     endTime=").append(endTime);
559         sb.append(    "\n   renewTill=").append(renewTill);
560         sb.append(    "\n       flags=").append(flags);
561         sb.append(    "\nEType (skey)=").append(key.getEType());
562         sb.append(    "\n   (tkt key)=").append(ticket.encPart.eType);
563         return sb.toString();
564     }
565 
toCCacheCreds()566     public sun.security.krb5.internal.ccache.Credentials toCCacheCreds() {
567         return new sun.security.krb5.internal.ccache.Credentials(
568                 getClient(), getServer(),
569                 getSessionKey(),
570                 date2kt(getAuthTime()),
571                 date2kt(getStartTime()),
572                 date2kt(getEndTime()),
573                 date2kt(getRenewTill()),
574                 false,
575                 flags,
576                 new HostAddresses(getClientAddresses()),
577                 getAuthzData(),
578                 getTicket(),
579                 null);
580     }
581 
date2kt(Date d)582     private static KerberosTime date2kt(Date d) {
583         return d == null ? null : new KerberosTime(d);
584     }
585 }
586