| /* |
| * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * |
| * (C) Copyright IBM Corp. 1999 All Rights Reserved. |
| * Copyright 1997 The Open Group Research Institute. All rights reserved. |
| */ |
| |
| package sun.security.krb5; |
| |
| import sun.security.krb5.internal.*; |
| import sun.security.krb5.internal.ccache.CredentialsCache; |
| import sun.security.krb5.internal.crypto.EType; |
| import java.io.IOException; |
| import java.util.Date; |
| import java.util.Locale; |
| import java.net.InetAddress; |
| |
| /** |
| * This class encapsulates the concept of a Kerberos service |
| * credential. That includes a Kerberos ticket and an associated |
| * session key. |
| */ |
| public class Credentials { |
| |
| Ticket ticket; |
| PrincipalName client; |
| PrincipalName server; |
| EncryptionKey key; |
| TicketFlags flags; |
| KerberosTime authTime; |
| KerberosTime startTime; |
| KerberosTime endTime; |
| KerberosTime renewTill; |
| HostAddresses cAddr; |
| EncryptionKey serviceKey; |
| AuthorizationData authzData; |
| private static boolean DEBUG = Krb5.DEBUG; |
| private static CredentialsCache cache; |
| static boolean alreadyLoaded = false; |
| private static boolean alreadyTried = false; |
| |
| // Read native ticket with session key type in the given list |
| private static native Credentials acquireDefaultNativeCreds(int[] eTypes); |
| |
| public Credentials(Ticket new_ticket, |
| PrincipalName new_client, |
| PrincipalName new_server, |
| EncryptionKey new_key, |
| TicketFlags new_flags, |
| KerberosTime authTime, |
| KerberosTime new_startTime, |
| KerberosTime new_endTime, |
| KerberosTime renewTill, |
| HostAddresses cAddr, |
| AuthorizationData authzData) { |
| this(new_ticket, new_client, new_server, new_key, new_flags, |
| authTime, new_startTime, new_endTime, renewTill, cAddr); |
| this.authzData = authzData; |
| } |
| |
| public Credentials(Ticket new_ticket, |
| PrincipalName new_client, |
| PrincipalName new_server, |
| EncryptionKey new_key, |
| TicketFlags new_flags, |
| KerberosTime authTime, |
| KerberosTime new_startTime, |
| KerberosTime new_endTime, |
| KerberosTime renewTill, |
| HostAddresses cAddr) { |
| ticket = new_ticket; |
| client = new_client; |
| server = new_server; |
| key = new_key; |
| flags = new_flags; |
| this.authTime = authTime; |
| startTime = new_startTime; |
| endTime = new_endTime; |
| this.renewTill = renewTill; |
| this.cAddr = cAddr; |
| } |
| |
| public Credentials(byte[] encoding, |
| String client, |
| String server, |
| byte[] keyBytes, |
| int keyType, |
| boolean[] flags, |
| Date authTime, |
| Date startTime, |
| Date endTime, |
| Date renewTill, |
| InetAddress[] cAddrs) throws KrbException, IOException { |
| this(new Ticket(encoding), |
| new PrincipalName(client, PrincipalName.KRB_NT_PRINCIPAL), |
| new PrincipalName(server, PrincipalName.KRB_NT_SRV_INST), |
| new EncryptionKey(keyType, keyBytes), |
| (flags == null? null: new TicketFlags(flags)), |
| (authTime == null? null: new KerberosTime(authTime)), |
| (startTime == null? null: new KerberosTime(startTime)), |
| (endTime == null? null: new KerberosTime(endTime)), |
| (renewTill == null? null: new KerberosTime(renewTill)), |
| null); // caddrs are in the encoding at this point |
| } |
| |
| /** |
| * Acquires a service ticket for the specified service |
| * principal. If the service ticket is not already available, it |
| * obtains a new one from the KDC. |
| */ |
| /* |
| public Credentials(Credentials tgt, PrincipalName service) |
| throws KrbException { |
| } |
| */ |
| |
| public final PrincipalName getClient() { |
| return client; |
| } |
| |
| public final PrincipalName getServer() { |
| return server; |
| } |
| |
| public final EncryptionKey getSessionKey() { |
| return key; |
| } |
| |
| public final Date getAuthTime() { |
| if (authTime != null) { |
| return authTime.toDate(); |
| } else { |
| return null; |
| } |
| } |
| |
| public final Date getStartTime() { |
| if (startTime != null) |
| { |
| return startTime.toDate(); |
| } |
| return null; |
| } |
| |
| public final Date getEndTime() { |
| if (endTime != null) |
| { |
| return endTime.toDate(); |
| } |
| return null; |
| } |
| |
| public final Date getRenewTill() { |
| if (renewTill != null) |
| { |
| return renewTill.toDate(); |
| } |
| return null; |
| } |
| |
| public final boolean[] getFlags() { |
| if (flags == null) // Can be in a KRB-CRED |
| return null; |
| return flags.toBooleanArray(); |
| } |
| |
| public final InetAddress[] getClientAddresses() { |
| |
| if (cAddr == null) |
| return null; |
| |
| return cAddr.getInetAddresses(); |
| } |
| |
| public final byte[] getEncoded() { |
| byte[] retVal = null; |
| try { |
| retVal = ticket.asn1Encode(); |
| } catch (Asn1Exception e) { |
| if (DEBUG) |
| System.out.println(e); |
| } catch (IOException ioe) { |
| if (DEBUG) |
| System.out.println(ioe); |
| } |
| return retVal; |
| } |
| |
| public boolean isForwardable() { |
| return flags.get(Krb5.TKT_OPTS_FORWARDABLE); |
| } |
| |
| public boolean isRenewable() { |
| return flags.get(Krb5.TKT_OPTS_RENEWABLE); |
| } |
| |
| public Ticket getTicket() { |
| return ticket; |
| } |
| |
| public TicketFlags getTicketFlags() { |
| return flags; |
| } |
| |
| public AuthorizationData getAuthzData() { |
| return authzData; |
| } |
| /** |
| * Checks if the service ticket returned by the KDC has the OK-AS-DELEGATE |
| * flag set |
| * @return true if OK-AS_DELEGATE flag is set, otherwise, return false. |
| */ |
| public boolean checkDelegate() { |
| return flags.get(Krb5.TKT_OPTS_DELEGATE); |
| } |
| |
| /** |
| * Reset TKT_OPTS_DELEGATE to false, called at credentials acquirement |
| * when one of the cross-realm TGTs does not have the OK-AS-DELEGATE |
| * flag set. This info must be preservable and restorable through |
| * the Krb5Util.credsToTicket/ticketToCreds() methods so that even if |
| * the service ticket is cached it still remembers the cross-realm |
| * authentication result. |
| */ |
| public void resetDelegate() { |
| flags.set(Krb5.TKT_OPTS_DELEGATE, false); |
| } |
| |
| public Credentials renew() throws KrbException, IOException { |
| KDCOptions options = new KDCOptions(); |
| options.set(KDCOptions.RENEW, true); |
| /* |
| * Added here to pass KrbKdcRep.check:73 |
| */ |
| options.set(KDCOptions.RENEWABLE, true); |
| |
| return new KrbTgsReq(options, |
| this, |
| server, |
| null, // from |
| null, // till |
| null, // rtime |
| null, // eTypes |
| cAddr, |
| null, |
| null, |
| null).sendAndGetCreds(); |
| } |
| |
| /** |
| * Returns a TGT for the given client principal from a ticket cache. |
| * |
| * @param princ the client principal. A value of null means that the |
| * default principal name in the credentials cache will be used. |
| * @param ticketCache the path to the tickets file. A value |
| * of null will be accepted to indicate that the default |
| * path should be searched |
| * @return the TGT credentials or null if none were found. If the tgt |
| * expired, it is the responsibility of the caller to determine this. |
| */ |
| public static Credentials acquireTGTFromCache(PrincipalName princ, |
| String ticketCache) |
| throws KrbException, IOException { |
| |
| if (ticketCache == null) { |
| // The default ticket cache on Windows and Mac is not a file. |
| String os = java.security.AccessController.doPrivileged( |
| new sun.security.action.GetPropertyAction("os.name")); |
| if (os.toUpperCase(Locale.ENGLISH).startsWith("WINDOWS") || |
| os.toUpperCase(Locale.ENGLISH).contains("OS X")) { |
| Credentials creds = acquireDefaultCreds(); |
| if (creds == null) { |
| if (DEBUG) { |
| System.out.println(">>> Found no TGT's in LSA"); |
| } |
| return null; |
| } |
| if (princ != null) { |
| if (creds.getClient().equals(princ)) { |
| if (DEBUG) { |
| System.out.println(">>> Obtained TGT from LSA: " |
| + creds); |
| } |
| return creds; |
| } else { |
| if (DEBUG) { |
| System.out.println(">>> LSA contains TGT for " |
| + creds.getClient() |
| + " not " |
| + princ); |
| } |
| return null; |
| } |
| } else { |
| if (DEBUG) { |
| System.out.println(">>> Obtained TGT from LSA: " |
| + creds); |
| } |
| return creds; |
| } |
| } |
| } |
| |
| /* |
| * Returns the appropriate cache. If ticketCache is null, it is the |
| * default cache otherwise it is the cache filename contained in it. |
| */ |
| CredentialsCache ccache = |
| CredentialsCache.getInstance(princ, ticketCache); |
| |
| if (ccache == null) { |
| return null; |
| } |
| |
| sun.security.krb5.internal.ccache.Credentials tgtCred = |
| ccache.getDefaultCreds(); |
| |
| if (tgtCred == null) { |
| return null; |
| } |
| |
| if (EType.isSupported(tgtCred.getEType())) { |
| return tgtCred.setKrbCreds(); |
| } else { |
| if (DEBUG) { |
| System.out.println( |
| ">>> unsupported key type found the default TGT: " + |
| tgtCred.getEType()); |
| } |
| return null; |
| } |
| } |
| |
| /** |
| * Acquires default credentials. |
| * <br>The possible locations for default credentials cache is searched in |
| * the following order: |
| * <ol> |
| * <li> The directory and cache file name specified by "KRB5CCNAME" system. |
| * property. |
| * <li> The directory and cache file name specified by "KRB5CCNAME" |
| * environment variable. |
| * <li> A cache file named krb5cc_{user.name} at {user.home} directory. |
| * </ol> |
| * @return a <code>KrbCreds</code> object if the credential is found, |
| * otherwise return null. |
| */ |
| |
| // this method is intentionally changed to not check if the caller's |
| // principal name matches cache file's principal name. |
| // It assumes that the GSS call has |
| // the privilege to access the default cache file. |
| |
| // This method is only called on Windows and Mac OS X, the native |
| // acquireDefaultNativeCreds is also available on these platforms. |
| public static synchronized Credentials acquireDefaultCreds() { |
| Credentials result = null; |
| |
| if (cache == null) { |
| cache = CredentialsCache.getInstance(); |
| } |
| if (cache != null) { |
| sun.security.krb5.internal.ccache.Credentials temp = |
| cache.getDefaultCreds(); |
| if (temp != null) { |
| if (DEBUG) { |
| System.out.println(">>> KrbCreds found the default ticket" |
| + " granting ticket in credential cache."); |
| } |
| if (EType.isSupported(temp.getEType())) { |
| result = temp.setKrbCreds(); |
| } else { |
| if (DEBUG) { |
| System.out.println( |
| ">>> unsupported key type found the default TGT: " + |
| temp.getEType()); |
| } |
| } |
| } |
| } |
| if (result == null) { |
| // Doesn't seem to be a default cache on this system or |
| // TGT has unsupported encryption type |
| |
| if (!alreadyTried) { |
| // See if there's any native code to load |
| try { |
| ensureLoaded(); |
| } catch (Exception e) { |
| if (DEBUG) { |
| System.out.println("Can not load credentials cache"); |
| e.printStackTrace(); |
| } |
| alreadyTried = true; |
| } |
| } |
| if (alreadyLoaded) { |
| // There is some native code |
| if (DEBUG) { |
| System.out.println(">> Acquire default native Credentials"); |
| } |
| try { |
| result = acquireDefaultNativeCreds( |
| EType.getDefaults("default_tkt_enctypes")); |
| } catch (KrbException ke) { |
| // when there is no default_tkt_enctypes. |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Acquires credentials for a specified service using initial credential. |
| * When the service has a different realm |
| * from the initial credential, we do cross-realm authentication |
| * - first, we use the current credential to get |
| * a cross-realm credential from the local KDC, then use that |
| * cross-realm credential to request service credential |
| * from the foreigh KDC. |
| * |
| * @param service the name of service principal using format |
| * components@realm |
| * @param ccreds client's initial credential. |
| * @exception IOException if an error occurs in reading the credentials |
| * cache |
| * @exception KrbException if an error occurs specific to Kerberos |
| * @return a <code>Credentials</code> object. |
| */ |
| |
| public static Credentials acquireServiceCreds(String service, |
| Credentials ccreds) |
| throws KrbException, IOException { |
| return CredentialsUtil.acquireServiceCreds(service, ccreds); |
| } |
| |
| public static Credentials acquireS4U2selfCreds(PrincipalName user, |
| Credentials ccreds) throws KrbException, IOException { |
| return CredentialsUtil.acquireS4U2selfCreds(user, ccreds); |
| } |
| |
| public static Credentials acquireS4U2proxyCreds(String service, |
| Ticket second, PrincipalName client, Credentials ccreds) |
| throws KrbException, IOException { |
| return CredentialsUtil.acquireS4U2proxyCreds( |
| service, second, client, ccreds); |
| } |
| |
| public CredentialsCache getCache() { |
| return cache; |
| } |
| |
| public EncryptionKey getServiceKey() { |
| return serviceKey; |
| } |
| |
| /* |
| * Prints out debug info. |
| */ |
| public static void printDebug(Credentials c) { |
| System.out.println(">>> DEBUG: ----Credentials----"); |
| System.out.println("\tclient: " + c.client.toString()); |
| System.out.println("\tserver: " + c.server.toString()); |
| System.out.println("\tticket: sname: " + c.ticket.sname.toString()); |
| if (c.startTime != null) { |
| System.out.println("\tstartTime: " + c.startTime.getTime()); |
| } |
| System.out.println("\tendTime: " + c.endTime.getTime()); |
| System.out.println(" ----Credentials end----"); |
| } |
| |
| |
| static void ensureLoaded() { |
| java.security.AccessController.doPrivileged( |
| new java.security.PrivilegedAction<Void> () { |
| public Void run() { |
| if (System.getProperty("os.name").contains("OS X")) { |
| System.loadLibrary("osxkrb5"); |
| } else { |
| System.loadLibrary("w2k_lsa_auth"); |
| } |
| return null; |
| } |
| }); |
| alreadyLoaded = true; |
| } |
| |
| public String toString() { |
| StringBuilder sb = new StringBuilder("Credentials:"); |
| sb.append( "\n client=").append(client); |
| sb.append( "\n server=").append(server); |
| if (authTime != null) { |
| sb.append("\n authTime=").append(authTime); |
| } |
| if (startTime != null) { |
| sb.append("\n startTime=").append(startTime); |
| } |
| sb.append( "\n endTime=").append(endTime); |
| sb.append( "\n renewTill=").append(renewTill); |
| sb.append( "\n flags=").append(flags); |
| sb.append( "\nEType (skey)=").append(key.getEType()); |
| sb.append( "\n (tkt key)=").append(ticket.encPart.eType); |
| return sb.toString(); |
| } |
| |
| public sun.security.krb5.internal.ccache.Credentials toCCacheCreds() { |
| return new sun.security.krb5.internal.ccache.Credentials( |
| getClient(), getServer(), |
| getSessionKey(), |
| date2kt(getAuthTime()), |
| date2kt(getStartTime()), |
| date2kt(getEndTime()), |
| date2kt(getRenewTill()), |
| false, |
| flags, |
| new HostAddresses(getClientAddresses()), |
| getAuthzData(), |
| getTicket(), |
| null); |
| } |
| |
| private static KerberosTime date2kt(Date d) { |
| return d == null ? null : new KerberosTime(d); |
| } |
| } |