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