Path: blob/master/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java
41159 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26*27* (C) Copyright IBM Corp. 1999 All Rights Reserved.28* Copyright 1997 The Open Group Research Institute. All rights reserved.29*/3031package sun.security.krb5;3233import sun.security.action.GetPropertyAction;34import sun.security.krb5.internal.*;35import sun.security.krb5.internal.ccache.CredentialsCache;36import sun.security.krb5.internal.crypto.EType;37import java.io.IOException;38import java.util.Date;39import java.util.Locale;40import java.net.InetAddress;4142/**43* This class encapsulates the concept of a Kerberos service44* credential. That includes a Kerberos ticket and an associated45* session key.46*/47public class Credentials {4849Ticket ticket;50PrincipalName client;51PrincipalName clientAlias;52PrincipalName server;53PrincipalName serverAlias;54EncryptionKey key;55TicketFlags flags;56KerberosTime authTime;57KerberosTime startTime;58KerberosTime endTime;59KerberosTime renewTill;60HostAddresses cAddr;61AuthorizationData authzData;62private static boolean DEBUG = Krb5.DEBUG;63private static CredentialsCache cache;64static boolean alreadyLoaded = false;65private static boolean alreadyTried = false;6667private Credentials proxy = null;6869public Credentials getProxy() {70return proxy;71}7273public Credentials setProxy(Credentials proxy) {74this.proxy = proxy;75return this;76}7778// Read native ticket with session key type in the given list79private static native Credentials acquireDefaultNativeCreds(int[] eTypes);8081public Credentials(Ticket new_ticket,82PrincipalName new_client,83PrincipalName new_client_alias,84PrincipalName new_server,85PrincipalName new_server_alias,86EncryptionKey new_key,87TicketFlags new_flags,88KerberosTime authTime,89KerberosTime new_startTime,90KerberosTime new_endTime,91KerberosTime renewTill,92HostAddresses cAddr,93AuthorizationData authzData) {94this(new_ticket, new_client, new_client_alias, new_server,95new_server_alias, new_key, new_flags, authTime,96new_startTime, new_endTime, renewTill, cAddr);97this.authzData = authzData;98}99100// Warning: called by NativeCreds.c and nativeccache.c101public Credentials(Ticket new_ticket,102PrincipalName new_client,103PrincipalName new_client_alias,104PrincipalName new_server,105PrincipalName new_server_alias,106EncryptionKey new_key,107TicketFlags new_flags,108KerberosTime authTime,109KerberosTime new_startTime,110KerberosTime new_endTime,111KerberosTime renewTill,112HostAddresses cAddr) {113ticket = new_ticket;114client = new_client;115clientAlias = new_client_alias;116server = new_server;117serverAlias = new_server_alias;118key = new_key;119flags = new_flags;120this.authTime = authTime;121startTime = new_startTime;122endTime = new_endTime;123this.renewTill = renewTill;124this.cAddr = cAddr;125}126127public Credentials(byte[] encoding,128String client,129String clientAlias,130String server,131String serverAlias,132byte[] keyBytes,133int keyType,134boolean[] flags,135Date authTime,136Date startTime,137Date endTime,138Date renewTill,139InetAddress[] cAddrs) throws KrbException, IOException {140this(new Ticket(encoding),141new PrincipalName(client, PrincipalName.KRB_NT_PRINCIPAL),142(clientAlias == null? null : new PrincipalName(clientAlias,143PrincipalName.KRB_NT_PRINCIPAL)),144new PrincipalName(server, PrincipalName.KRB_NT_SRV_INST),145(serverAlias == null? null : new PrincipalName(serverAlias,146PrincipalName.KRB_NT_SRV_INST)),147new 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)),153null); // caddrs are in the encoding at this point154}155156/**157* Acquires a service ticket for the specified service158* principal. If the service ticket is not already available, it159* obtains a new one from the KDC.160*/161/*162public Credentials(Credentials tgt, PrincipalName service)163throws KrbException {164}165*/166167public final PrincipalName getClient() {168return client;169}170171public final PrincipalName getClientAlias() {172return clientAlias;173}174175public final PrincipalName getServer() {176return server;177}178179public final PrincipalName getServerAlias() {180return serverAlias;181}182183public final EncryptionKey getSessionKey() {184return key;185}186187public final Date getAuthTime() {188if (authTime != null) {189return authTime.toDate();190} else {191return null;192}193}194195public final Date getStartTime() {196if (startTime != null)197{198return startTime.toDate();199}200return null;201}202203public final Date getEndTime() {204if (endTime != null)205{206return endTime.toDate();207}208return null;209}210211public final Date getRenewTill() {212if (renewTill != null)213{214return renewTill.toDate();215}216return null;217}218219public final boolean[] getFlags() {220if (flags == null) // Can be in a KRB-CRED221return null;222return flags.toBooleanArray();223}224225public final InetAddress[] getClientAddresses() {226227if (cAddr == null)228return null;229230return cAddr.getInetAddresses();231}232233public final byte[] getEncoded() {234byte[] retVal = null;235try {236retVal = ticket.asn1Encode();237} catch (Asn1Exception e) {238if (DEBUG) {239System.out.println(e);240}241} catch (IOException ioe) {242if (DEBUG) {243System.out.println(ioe);244}245}246return retVal;247}248249public boolean isForwardable() {250return flags.get(Krb5.TKT_OPTS_FORWARDABLE);251}252253public boolean isRenewable() {254return flags.get(Krb5.TKT_OPTS_RENEWABLE);255}256257public Ticket getTicket() {258return ticket;259}260261public TicketFlags getTicketFlags() {262return flags;263}264265public AuthorizationData getAuthzData() {266return authzData;267}268/**269* Checks if the service ticket returned by the KDC has the OK-AS-DELEGATE270* flag set271* @return true if OK-AS_DELEGATE flag is set, otherwise, return false.272*/273public boolean checkDelegate() {274return flags.get(Krb5.TKT_OPTS_DELEGATE);275}276277/**278* Reset TKT_OPTS_DELEGATE to false, called at credentials acquirement279* when one of the cross-realm TGTs does not have the OK-AS-DELEGATE280* flag set. This info must be preservable and restorable through281* the Krb5Util.credsToTicket/ticketToCreds() methods so that even if282* the service ticket is cached it still remembers the cross-realm283* authentication result.284*/285public void resetDelegate() {286flags.set(Krb5.TKT_OPTS_DELEGATE, false);287}288289public Credentials renew() throws KrbException, IOException {290KDCOptions options = new KDCOptions();291options.set(KDCOptions.RENEW, true);292/*293* Added here to pass KrbKdcRep.check:73294*/295options.set(KDCOptions.RENEWABLE, true);296297return new KrbTgsReq(options,298this,299server,300serverAlias,301null, // from302null, // till303null, // rtime304null, // eTypes305cAddr,306null,307null,308null).sendAndGetCreds();309}310311/**312* Returns a TGT for the given client principal from a ticket cache.313*314* @param princ the client principal. A value of null means that the315* default principal name in the credentials cache will be used.316* @param ticketCache the path to the tickets file. A value317* of null will be accepted to indicate that the default318* path should be searched319* @return the TGT credentials or null if none were found. If the tgt320* expired, it is the responsibility of the caller to determine this.321*/322public static Credentials acquireTGTFromCache(PrincipalName princ,323String ticketCache)324throws KrbException, IOException {325326if (ticketCache == null) {327// The default ticket cache on Windows and Mac is not a file.328String os = GetPropertyAction.privilegedGetProperty("os.name");329if (os.toUpperCase(Locale.ENGLISH).startsWith("WINDOWS") ||330os.toUpperCase(Locale.ENGLISH).contains("OS X")) {331Credentials creds = acquireDefaultCreds();332if (creds == null) {333if (DEBUG) {334System.out.println(">>> Found no TGT's in native ccache");335}336return null;337}338if (princ != null) {339if (creds.getClient().equals(princ)) {340if (DEBUG) {341System.out.println(">>> Obtained TGT from native ccache: "342+ creds);343}344return creds;345} else {346if (DEBUG) {347System.out.println(">>> native ccache contains TGT for "348+ creds.getClient()349+ " not "350+ princ);351}352return null;353}354} else {355if (DEBUG) {356System.out.println(">>> Obtained TGT from native ccache: "357+ creds);358}359return creds;360}361}362}363364/*365* Returns the appropriate cache. If ticketCache is null, it is the366* default cache otherwise it is the cache filename contained in it.367*/368CredentialsCache ccache =369CredentialsCache.getInstance(princ, ticketCache);370371if (ccache == null) {372return null;373}374375Credentials tgtCred = ccache.getInitialCreds();376377if (tgtCred == null) {378return null;379}380381if (EType.isSupported(tgtCred.key.getEType())) {382return tgtCred;383} else {384if (DEBUG) {385System.out.println(386">>> unsupported key type found the default TGT: " +387tgtCred.key.getEType());388}389return null;390}391}392393/**394* Acquires default credentials.395* <br>The possible locations for default credentials cache is searched in396* the following order:397* <ol>398* <li> The directory and cache file name specified by "KRB5CCNAME" system.399* property.400* <li> The directory and cache file name specified by "KRB5CCNAME"401* environment variable.402* <li> A cache file named krb5cc_{user.name} at {user.home} directory.403* </ol>404* @return a <code>KrbCreds</code> object if the credential is found,405* otherwise return null.406*/407408// this method is intentionally changed to not check if the caller's409// principal name matches cache file's principal name.410// It assumes that the GSS call has411// the privilege to access the default cache file.412413// This method is only called on Windows and Mac OS X, the native414// acquireDefaultNativeCreds is also available on these platforms.415public static synchronized Credentials acquireDefaultCreds() {416Credentials result = null;417418if (cache == null) {419cache = CredentialsCache.getInstance();420}421if (cache != null) {422Credentials temp = cache.getInitialCreds();423if (temp != null) {424if (DEBUG) {425System.out.println(">>> KrbCreds found the default ticket"426+ " granting ticket in credential cache.");427}428if (EType.isSupported(temp.key.getEType())) {429result = temp;430} else {431if (DEBUG) {432System.out.println(433">>> unsupported key type found the default TGT: " +434temp.key.getEType());435}436}437}438}439if (result == null) {440// Doesn't seem to be a default cache on this system or441// TGT has unsupported encryption type442443if (!alreadyTried) {444// See if there's any native code to load445try {446ensureLoaded();447} catch (Exception e) {448if (DEBUG) {449System.out.println("Can not load native ccache library");450e.printStackTrace();451}452alreadyTried = true;453}454}455if (alreadyLoaded) {456// There is some native code457if (DEBUG) {458System.out.println(">> Acquire default native Credentials");459}460try {461result = acquireDefaultNativeCreds(462EType.getDefaults("default_tkt_enctypes"));463} catch (KrbException ke) {464// when there is no default_tkt_enctypes.465}466}467}468return result;469}470471/**472* Acquires credentials for a specified service using initial credential.473* When the service has a different realm474* from the initial credential, we do cross-realm authentication475* - first, we use the current credential to get476* a cross-realm credential from the local KDC, then use that477* cross-realm credential to request service credential478* from the foreigh KDC.479*480* @param service the name of service principal using format481* components@realm482* @param ccreds client's initial credential.483* @exception IOException if an error occurs in reading the credentials484* cache485* @exception KrbException if an error occurs specific to Kerberos486* @return a <code>Credentials</code> object.487*/488489public static Credentials acquireServiceCreds(String service,490Credentials ccreds)491throws KrbException, IOException {492return CredentialsUtil.acquireServiceCreds(service, ccreds);493}494495public static Credentials acquireS4U2selfCreds(PrincipalName user,496Credentials ccreds) throws KrbException, IOException {497return CredentialsUtil.acquireS4U2selfCreds(user, ccreds);498}499500public static Credentials acquireS4U2proxyCreds(String service,501Ticket second, PrincipalName client, Credentials ccreds)502throws KrbException, IOException {503return CredentialsUtil.acquireS4U2proxyCreds(504service, second, client, ccreds);505}506507public CredentialsCache getCache() {508return cache;509}510511/*512* Prints out debug info.513*/514public static void printDebug(Credentials c) {515System.out.println(">>> DEBUG: ----Credentials----");516System.out.println("\tclient: " + c.client.toString());517if (c.clientAlias != null)518System.out.println("\tclient alias: " + c.clientAlias.toString());519System.out.println("\tserver: " + c.server.toString());520if (c.serverAlias != null)521System.out.println("\tserver alias: " + c.serverAlias.toString());522System.out.println("\tticket: sname: " + c.ticket.sname.toString());523if (c.startTime != null) {524System.out.println("\tstartTime: " + c.startTime.getTime());525}526System.out.println("\tendTime: " + c.endTime.getTime());527System.out.println(" ----Credentials end----");528}529530531@SuppressWarnings("removal")532static void ensureLoaded() {533java.security.AccessController.doPrivileged(534new java.security.PrivilegedAction<Void> () {535public Void run() {536if (System.getProperty("os.name").contains("OS X")) {537System.loadLibrary("osxkrb5");538} else {539System.loadLibrary("w2k_lsa_auth");540}541return null;542}543});544alreadyLoaded = true;545}546547public String toString() {548StringBuilder sb = new StringBuilder("Credentials:");549sb.append( "\n client=").append(client);550if (clientAlias != null)551sb.append( "\n clientAlias=").append(clientAlias);552sb.append( "\n server=").append(server);553if (serverAlias != null)554sb.append( "\n serverAlias=").append(serverAlias);555if (authTime != null) {556sb.append("\n authTime=").append(authTime);557}558if (startTime != null) {559sb.append("\n startTime=").append(startTime);560}561sb.append( "\n endTime=").append(endTime);562sb.append( "\n renewTill=").append(renewTill);563sb.append( "\n flags=").append(flags);564sb.append( "\nEType (skey)=").append(key.getEType());565sb.append( "\n (tkt key)=").append(ticket.encPart.eType);566return sb.toString();567}568569public sun.security.krb5.internal.ccache.Credentials toCCacheCreds() {570return new sun.security.krb5.internal.ccache.Credentials(571getClient(), getServer(),572getSessionKey(),573date2kt(getAuthTime()),574date2kt(getStartTime()),575date2kt(getEndTime()),576date2kt(getRenewTill()),577false,578flags,579new HostAddresses(getClientAddresses()),580getAuthzData(),581getTicket(),582null);583}584585private static KerberosTime date2kt(Date d) {586return d == null ? null : new KerberosTime(d);587}588}589590591