0N/A/*
2362N/A * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.security.auth.kerberos;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.util.Date;
0N/Aimport java.util.Arrays;
0N/Aimport java.net.InetAddress;
0N/Aimport javax.crypto.SecretKey;
0N/Aimport javax.security.auth.Refreshable;
0N/Aimport javax.security.auth.Destroyable;
0N/Aimport javax.security.auth.RefreshFailedException;
0N/Aimport javax.security.auth.DestroyFailedException;
0N/Aimport sun.misc.HexDumpEncoder;
0N/Aimport sun.security.krb5.EncryptionKey;
0N/Aimport sun.security.krb5.Asn1Exception;
0N/Aimport sun.security.util.*;
0N/A
0N/A/**
0N/A * This class encapsulates a Kerberos ticket and associated
0N/A * information as viewed from the client's point of view. It captures all
0N/A * information that the Key Distribution Center (KDC) sends to the client
0N/A * in the reply message KDC-REP defined in the Kerberos Protocol
0N/A * Specification (<a href=http://www.ietf.org/rfc/rfc4120.txt>RFC 4120</a>).
0N/A * <p>
0N/A * All Kerberos JAAS login modules that authenticate a user to a KDC should
0N/A * use this class. Where available, the login module might even read this
0N/A * information from a ticket cache in the operating system instead of
0N/A * directly communicating with the KDC. During the commit phase of the JAAS
0N/A * authentication process, the JAAS login module should instantiate this
0N/A * class and store the instance in the private credential set of a
0N/A * {@link javax.security.auth.Subject Subject}.<p>
0N/A *
0N/A * It might be necessary for the application to be granted a
0N/A * {@link javax.security.auth.PrivateCredentialPermission
0N/A * PrivateCredentialPermission} if it needs to access a KerberosTicket
0N/A * instance from a Subject. This permission is not needed when the
0N/A * application depends on the default JGSS Kerberos mechanism to access the
0N/A * KerberosTicket. In that case, however, the application will need an
0N/A * appropriate
0N/A * {@link javax.security.auth.kerberos.ServicePermission ServicePermission}.
0N/A * <p>
0N/A * Note that this class is applicable to both ticket granting tickets and
0N/A * other regular service tickets. A ticket granting ticket is just a
0N/A * special case of a more generalized service ticket.
0N/A *
0N/A * @see javax.security.auth.Subject
0N/A * @see javax.security.auth.PrivateCredentialPermission
0N/A * @see javax.security.auth.login.LoginContext
0N/A * @see org.ietf.jgss.GSSCredential
0N/A * @see org.ietf.jgss.GSSManager
0N/A *
0N/A * @author Mayank Upadhyay
0N/A * @since 1.4
0N/A */
0N/Apublic class KerberosTicket implements Destroyable, Refreshable,
0N/A java.io.Serializable {
0N/A
0N/A private static final long serialVersionUID = 7395334370157380539L;
0N/A
0N/A // XXX Make these flag indices public
0N/A private static final int FORWARDABLE_TICKET_FLAG = 1;
0N/A private static final int FORWARDED_TICKET_FLAG = 2;
0N/A private static final int PROXIABLE_TICKET_FLAG = 3;
0N/A private static final int PROXY_TICKET_FLAG = 4;
0N/A private static final int POSTDATED_TICKET_FLAG = 6;
0N/A private static final int RENEWABLE_TICKET_FLAG = 8;
0N/A private static final int INITIAL_TICKET_FLAG = 9;
0N/A
0N/A private static final int NUM_FLAGS = 32;
0N/A
0N/A /**
0N/A *
0N/A * ASN.1 DER Encoding of the Ticket as defined in the
0N/A * Kerberos Protocol Specification RFC4120.
0N/A *
0N/A * @serial
0N/A */
0N/A
0N/A private byte[] asn1Encoding;
0N/A
0N/A /**
0N/A *<code>KeyImpl</code> is serialized by writing out the ASN1 Encoded bytes
0N/A * of the encryption key. The ASN1 encoding is defined in RFC4120 and as
0N/A * follows:
0N/A * <pre>
0N/A * EncryptionKey ::= SEQUENCE {
0N/A * keytype [0] Int32 -- actually encryption type --,
0N/A * keyvalue [1] OCTET STRING
0N/A * }
0N/A * </pre>
0N/A *
0N/A * @serial
0N/A */
0N/A
0N/A private KeyImpl sessionKey;
0N/A
0N/A /**
0N/A *
0N/A * Ticket Flags as defined in the Kerberos Protocol Specification RFC4120.
0N/A *
0N/A * @serial
0N/A */
0N/A
0N/A private boolean[] flags;
0N/A
0N/A /**
0N/A *
0N/A * Time of initial authentication
0N/A *
0N/A * @serial
0N/A */
0N/A
0N/A private Date authTime;
0N/A
0N/A /**
0N/A *
0N/A * Time after which the ticket is valid.
0N/A * @serial
0N/A */
0N/A private Date startTime;
0N/A
0N/A /**
0N/A *
0N/A * Time after which the ticket will not be honored. (its expiration time).
0N/A *
0N/A * @serial
0N/A */
0N/A
0N/A private Date endTime;
0N/A
0N/A /**
0N/A *
0N/A * For renewable Tickets it indicates the maximum endtime that may be
0N/A * included in a renewal. It can be thought of as the absolute expiration
0N/A * time for the ticket, including all renewals. This field may be null
0N/A * for tickets that are not renewable.
0N/A *
0N/A * @serial
0N/A */
0N/A
0N/A private Date renewTill;
0N/A
0N/A /**
0N/A *
0N/A * Client that owns the service ticket
0N/A *
0N/A * @serial
0N/A */
0N/A
0N/A private KerberosPrincipal client;
0N/A
0N/A /**
0N/A *
0N/A * The service for which the ticket was issued.
0N/A *
0N/A * @serial
0N/A */
0N/A
0N/A private KerberosPrincipal server;
0N/A
0N/A /**
0N/A *
0N/A * The addresses from where the ticket may be used by the client.
0N/A * This field may be null when the ticket is usable from any address.
0N/A *
0N/A * @serial
0N/A */
0N/A
0N/A
0N/A private InetAddress[] clientAddresses;
0N/A
0N/A private transient boolean destroyed = false;
0N/A
0N/A /**
0N/A * Constructs a KerberosTicket using credentials information that a
0N/A * client either receives from a KDC or reads from a cache.
0N/A *
0N/A * @param asn1Encoding the ASN.1 encoding of the ticket as defined by
0N/A * the Kerberos protocol specification.
0N/A * @param client the client that owns this service
0N/A * ticket
0N/A * @param server the service that this ticket is for
0N/A * @param sessionKey the raw bytes for the session key that must be
0N/A * used to encrypt the authenticator that will be sent to the server
0N/A * @param keyType the key type for the session key as defined by the
0N/A * Kerberos protocol specification.
0N/A * @param flags the ticket flags. Each element in this array indicates
0N/A * the value for the corresponding bit in the ASN.1 BitString that
0N/A * represents the ticket flags. If the number of elements in this array
0N/A * is less than the number of flags used by the Kerberos protocol,
0N/A * then the missing flags will be filled in with false.
0N/A * @param authTime the time of initial authentication for the client
0N/A * @param startTime the time after which the ticket will be valid. This
0N/A * may be null in which case the value of authTime is treated as the
0N/A * startTime.
0N/A * @param endTime the time after which the ticket will no longer be
0N/A * valid
0N/A * @param renewTill an absolute expiration time for the ticket,
0N/A * including all renewal that might be possible. This field may be null
0N/A * for tickets that are not renewable.
0N/A * @param clientAddresses the addresses from where the ticket may be
0N/A * used by the client. This field may be null when the ticket is usable
0N/A * from any address.
0N/A */
0N/A public KerberosTicket(byte[] asn1Encoding,
0N/A KerberosPrincipal client,
0N/A KerberosPrincipal server,
0N/A byte[] sessionKey,
0N/A int keyType,
0N/A boolean[] flags,
0N/A Date authTime,
0N/A Date startTime,
0N/A Date endTime,
0N/A Date renewTill,
0N/A InetAddress[] clientAddresses) {
0N/A
0N/A init(asn1Encoding, client, server, sessionKey, keyType, flags,
0N/A authTime, startTime, endTime, renewTill, clientAddresses);
0N/A }
0N/A
0N/A private void init(byte[] asn1Encoding,
0N/A KerberosPrincipal client,
0N/A KerberosPrincipal server,
0N/A byte[] sessionKey,
0N/A int keyType,
0N/A boolean[] flags,
0N/A Date authTime,
0N/A Date startTime,
0N/A Date endTime,
0N/A Date renewTill,
0N/A InetAddress[] clientAddresses) {
265N/A if (sessionKey == null)
265N/A throw new IllegalArgumentException("Session key for ticket"
265N/A + " cannot be null");
265N/A init(asn1Encoding, client, server,
265N/A new KeyImpl(sessionKey, keyType), flags, authTime,
265N/A startTime, endTime, renewTill, clientAddresses);
265N/A }
0N/A
265N/A private void init(byte[] asn1Encoding,
265N/A KerberosPrincipal client,
265N/A KerberosPrincipal server,
265N/A KeyImpl sessionKey,
265N/A boolean[] flags,
265N/A Date authTime,
265N/A Date startTime,
265N/A Date endTime,
265N/A Date renewTill,
265N/A InetAddress[] clientAddresses) {
0N/A if (asn1Encoding == null)
0N/A throw new IllegalArgumentException("ASN.1 encoding of ticket"
0N/A + " cannot be null");
0N/A this.asn1Encoding = asn1Encoding.clone();
0N/A
0N/A if (client == null)
0N/A throw new IllegalArgumentException("Client name in ticket"
0N/A + " cannot be null");
0N/A this.client = client;
0N/A
0N/A if (server == null)
0N/A throw new IllegalArgumentException("Server name in ticket"
0N/A + " cannot be null");
0N/A this.server = server;
0N/A
265N/A // Caller needs to make sure `sessionKey` will not be null
265N/A this.sessionKey = sessionKey;
0N/A
0N/A if (flags != null) {
0N/A if (flags.length >= NUM_FLAGS)
28N/A this.flags = flags.clone();
0N/A else {
0N/A this.flags = new boolean[NUM_FLAGS];
0N/A // Fill in whatever we have
0N/A for (int i = 0; i < flags.length; i++)
0N/A this.flags[i] = flags[i];
0N/A }
0N/A } else
0N/A this.flags = new boolean[NUM_FLAGS];
0N/A
0N/A if (this.flags[RENEWABLE_TICKET_FLAG]) {
0N/A if (renewTill == null)
0N/A throw new IllegalArgumentException("The renewable period "
0N/A + "end time cannot be null for renewable tickets.");
0N/A
265N/A this.renewTill = new Date(renewTill.getTime());
0N/A }
0N/A
265N/A if (authTime != null) {
265N/A this.authTime = new Date(authTime.getTime());
265N/A }
265N/A if (startTime != null) {
265N/A this.startTime = new Date(startTime.getTime());
265N/A } else {
265N/A this.startTime = this.authTime;
265N/A }
0N/A
0N/A if (endTime == null)
0N/A throw new IllegalArgumentException("End time for ticket validity"
0N/A + " cannot be null");
265N/A this.endTime = new Date(endTime.getTime());
0N/A
0N/A if (clientAddresses != null)
28N/A this.clientAddresses = clientAddresses.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns the client principal associated with this ticket.
0N/A *
0N/A * @return the client principal.
0N/A */
0N/A public final KerberosPrincipal getClient() {
0N/A return client;
0N/A }
0N/A
0N/A /**
0N/A * Returns the service principal associated with this ticket.
0N/A *
0N/A * @return the service principal.
0N/A */
0N/A public final KerberosPrincipal getServer() {
0N/A return server;
0N/A }
0N/A
0N/A /**
0N/A * Returns the session key associated with this ticket.
0N/A *
0N/A * @return the session key.
0N/A */
0N/A public final SecretKey getSessionKey() {
0N/A if (destroyed)
0N/A throw new IllegalStateException("This ticket is no longer valid");
0N/A return sessionKey;
0N/A }
0N/A
0N/A /**
0N/A * Returns the key type of the session key associated with this
0N/A * ticket as defined by the Kerberos Protocol Specification.
0N/A *
0N/A * @return the key type of the session key associated with this
0N/A * ticket.
0N/A *
0N/A * @see #getSessionKey()
0N/A */
0N/A public final int getSessionKeyType() {
0N/A if (destroyed)
0N/A throw new IllegalStateException("This ticket is no longer valid");
0N/A return sessionKey.getKeyType();
0N/A }
0N/A
0N/A /**
0N/A * Determines if this ticket is forwardable.
0N/A *
0N/A * @return true if this ticket is forwardable, false if not.
0N/A */
0N/A public final boolean isForwardable() {
0N/A return flags[FORWARDABLE_TICKET_FLAG];
0N/A }
0N/A
0N/A /**
0N/A * Determines if this ticket had been forwarded or was issued based on
0N/A * authentication involving a forwarded ticket-granting ticket.
0N/A *
0N/A * @return true if this ticket had been forwarded or was issued based on
0N/A * authentication involving a forwarded ticket-granting ticket,
0N/A * false otherwise.
0N/A */
0N/A public final boolean isForwarded() {
0N/A return flags[FORWARDED_TICKET_FLAG];
0N/A }
0N/A
0N/A /**
0N/A * Determines if this ticket is proxiable.
0N/A *
0N/A * @return true if this ticket is proxiable, false if not.
0N/A */
0N/A public final boolean isProxiable() {
0N/A return flags[PROXIABLE_TICKET_FLAG];
0N/A }
0N/A
0N/A /**
0N/A * Determines is this ticket is a proxy-ticket.
0N/A *
0N/A * @return true if this ticket is a proxy-ticket, false if not.
0N/A */
0N/A public final boolean isProxy() {
0N/A return flags[PROXY_TICKET_FLAG];
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Determines is this ticket is post-dated.
0N/A *
0N/A * @return true if this ticket is post-dated, false if not.
0N/A */
0N/A public final boolean isPostdated() {
0N/A return flags[POSTDATED_TICKET_FLAG];
0N/A }
0N/A
0N/A /**
0N/A * Determines is this ticket is renewable. If so, the {@link #refresh()
0N/A * refresh} method can be called, assuming the validity period for
0N/A * renewing is not already over.
0N/A *
0N/A * @return true if this ticket is renewable, false if not.
0N/A */
0N/A public final boolean isRenewable() {
0N/A return flags[RENEWABLE_TICKET_FLAG];
0N/A }
0N/A
0N/A /**
0N/A * Determines if this ticket was issued using the Kerberos AS-Exchange
0N/A * protocol, and not issued based on some ticket-granting ticket.
0N/A *
0N/A * @return true if this ticket was issued using the Kerberos AS-Exchange
0N/A * protocol, false if not.
0N/A */
0N/A public final boolean isInitial() {
0N/A return flags[INITIAL_TICKET_FLAG];
0N/A }
0N/A
0N/A /**
0N/A * Returns the flags associated with this ticket. Each element in the
0N/A * returned array indicates the value for the corresponding bit in the
0N/A * ASN.1 BitString that represents the ticket flags.
0N/A *
0N/A * @return the flags associated with this ticket.
0N/A */
0N/A public final boolean[] getFlags() {
28N/A return (flags == null? null: flags.clone());
0N/A }
0N/A
0N/A /**
0N/A * Returns the time that the client was authenticated.
0N/A *
0N/A * @return the time that the client was authenticated
0N/A * or null if not set.
0N/A */
0N/A public final java.util.Date getAuthTime() {
265N/A return (authTime == null) ? null : (Date)authTime.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns the start time for this ticket's validity period.
0N/A *
0N/A * @return the start time for this ticket's validity period
0N/A * or null if not set.
0N/A */
0N/A public final java.util.Date getStartTime() {
265N/A return (startTime == null) ? null : (Date)startTime.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns the expiration time for this ticket's validity period.
0N/A *
0N/A * @return the expiration time for this ticket's validity period.
0N/A */
0N/A public final java.util.Date getEndTime() {
265N/A return (Date) endTime.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns the latest expiration time for this ticket, including all
0N/A * renewals. This will return a null value for non-renewable tickets.
0N/A *
0N/A * @return the latest expiration time for this ticket.
0N/A */
0N/A public final java.util.Date getRenewTill() {
265N/A return (renewTill == null) ? null: (Date)renewTill.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns a list of addresses from where the ticket can be used.
0N/A *
0N/A * @return ths list of addresses or null, if the field was not
0N/A * provided.
0N/A */
0N/A public final java.net.InetAddress[] getClientAddresses() {
28N/A return (clientAddresses == null) ? null: clientAddresses.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns an ASN.1 encoding of the entire ticket.
0N/A *
0N/A * @return an ASN.1 encoding of the entire ticket.
0N/A */
0N/A public final byte[] getEncoded() {
0N/A if (destroyed)
0N/A throw new IllegalStateException("This ticket is no longer valid");
28N/A return asn1Encoding.clone();
0N/A }
0N/A
0N/A /** Determines if this ticket is still current. */
0N/A public boolean isCurrent() {
0N/A return (System.currentTimeMillis() <= getEndTime().getTime());
0N/A }
0N/A
0N/A /**
0N/A * Extends the validity period of this ticket. The ticket will contain
0N/A * a new session key if the refresh operation succeeds. The refresh
0N/A * operation will fail if the ticket is not renewable or the latest
0N/A * allowable renew time has passed. Any other error returned by the
0N/A * KDC will also cause this method to fail.
0N/A *
0N/A * Note: This method is not synchronized with the the accessor
0N/A * methods of this object. Hence callers need to be aware of multiple
0N/A * threads that might access this and try to renew it at the same
0N/A * time.
0N/A *
0N/A * @throws RefreshFailedException if the ticket is not renewable, or
0N/A * the latest allowable renew time has passed, or the KDC returns some
0N/A * error.
0N/A *
0N/A * @see #isRenewable()
0N/A * @see #getRenewTill()
0N/A */
0N/A public void refresh() throws RefreshFailedException {
0N/A
0N/A if (destroyed)
0N/A throw new RefreshFailedException("A destroyed ticket "
0N/A + "cannot be renewd.");
0N/A
0N/A if (!isRenewable())
0N/A throw new RefreshFailedException("This ticket is not renewable");
0N/A
0N/A if (System.currentTimeMillis() > getRenewTill().getTime())
0N/A throw new RefreshFailedException("This ticket is past "
0N/A + "its last renewal time.");
0N/A Throwable e = null;
0N/A sun.security.krb5.Credentials krb5Creds = null;
0N/A
0N/A try {
0N/A krb5Creds = new sun.security.krb5.Credentials(asn1Encoding,
0N/A client.toString(),
0N/A server.toString(),
0N/A sessionKey.getEncoded(),
0N/A sessionKey.getKeyType(),
0N/A flags,
0N/A authTime,
0N/A startTime,
0N/A endTime,
0N/A renewTill,
0N/A clientAddresses);
0N/A krb5Creds = krb5Creds.renew();
0N/A } catch (sun.security.krb5.KrbException krbException) {
0N/A e = krbException;
0N/A } catch (java.io.IOException ioException) {
0N/A e = ioException;
0N/A }
0N/A
0N/A if (e != null) {
0N/A RefreshFailedException rfException
0N/A = new RefreshFailedException("Failed to renew Kerberos Ticket "
0N/A + "for client " + client
0N/A + " and server " + server
0N/A + " - " + e.getMessage());
0N/A rfException.initCause(e);
0N/A throw rfException;
0N/A }
0N/A
0N/A /*
0N/A * In case multiple threads try to refresh it at the same time.
0N/A */
0N/A synchronized (this) {
0N/A try {
0N/A this.destroy();
0N/A } catch (DestroyFailedException dfException) {
0N/A // Squelch it since we don't care about the old ticket.
0N/A }
0N/A init(krb5Creds.getEncoded(),
0N/A new KerberosPrincipal(krb5Creds.getClient().getName()),
0N/A new KerberosPrincipal(krb5Creds.getServer().getName(),
0N/A KerberosPrincipal.KRB_NT_SRV_INST),
0N/A krb5Creds.getSessionKey().getBytes(),
0N/A krb5Creds.getSessionKey().getEType(),
0N/A krb5Creds.getFlags(),
0N/A krb5Creds.getAuthTime(),
0N/A krb5Creds.getStartTime(),
0N/A krb5Creds.getEndTime(),
0N/A krb5Creds.getRenewTill(),
0N/A krb5Creds.getClientAddresses());
0N/A destroyed = false;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Destroys the ticket and destroys any sensitive information stored in
0N/A * it.
0N/A */
0N/A public void destroy() throws DestroyFailedException {
0N/A if (!destroyed) {
0N/A Arrays.fill(asn1Encoding, (byte) 0);
0N/A client = null;
0N/A server = null;
0N/A sessionKey.destroy();
0N/A flags = null;
0N/A authTime = null;
0N/A startTime = null;
0N/A endTime = null;
0N/A renewTill = null;
0N/A clientAddresses = null;
0N/A destroyed = true;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Determines if this ticket has been destroyed.
0N/A */
0N/A public boolean isDestroyed() {
0N/A return destroyed;
0N/A }
0N/A
0N/A public String toString() {
0N/A if (destroyed)
0N/A throw new IllegalStateException("This ticket is no longer valid");
0N/A StringBuffer caddrBuf = new StringBuffer();
0N/A if (clientAddresses != null) {
0N/A for (int i = 0; i < clientAddresses.length; i++) {
0N/A caddrBuf.append("clientAddresses[" + i + "] = " +
0N/A clientAddresses[i].toString());
0N/A }
0N/A }
0N/A return ("Ticket (hex) = " + "\n" +
0N/A (new HexDumpEncoder()).encodeBuffer(asn1Encoding) + "\n" +
0N/A "Client Principal = " + client.toString() + "\n" +
0N/A "Server Principal = " + server.toString() + "\n" +
0N/A "Session Key = " + sessionKey.toString() + "\n" +
0N/A "Forwardable Ticket " + flags[FORWARDABLE_TICKET_FLAG] + "\n" +
0N/A "Forwarded Ticket " + flags[FORWARDED_TICKET_FLAG] + "\n" +
0N/A "Proxiable Ticket " + flags[PROXIABLE_TICKET_FLAG] + "\n" +
0N/A "Proxy Ticket " + flags[PROXY_TICKET_FLAG] + "\n" +
0N/A "Postdated Ticket " + flags[POSTDATED_TICKET_FLAG] + "\n" +
0N/A "Renewable Ticket " + flags[RENEWABLE_TICKET_FLAG] + "\n" +
0N/A "Initial Ticket " + flags[RENEWABLE_TICKET_FLAG] + "\n" +
0N/A "Auth Time = " + String.valueOf(authTime) + "\n" +
0N/A "Start Time = " + String.valueOf(startTime) + "\n" +
0N/A "End Time = " + endTime.toString() + "\n" +
0N/A "Renew Till = " + String.valueOf(renewTill) + "\n" +
0N/A "Client Addresses " +
0N/A (clientAddresses == null ? " Null " : caddrBuf.toString() +
0N/A "\n"));
0N/A }
0N/A
0N/A /**
0N/A * Returns a hashcode for this KerberosTicket.
0N/A *
0N/A * @return a hashCode() for the <code>KerberosTicket</code>
0N/A * @since 1.6
0N/A */
0N/A public int hashCode() {
0N/A int result = 17;
0N/A if (isDestroyed()) {
0N/A return result;
0N/A }
0N/A result = result * 37 + Arrays.hashCode(getEncoded());
0N/A result = result * 37 + endTime.hashCode();
0N/A result = result * 37 + client.hashCode();
0N/A result = result * 37 + server.hashCode();
0N/A result = result * 37 + sessionKey.hashCode();
0N/A
0N/A // authTime may be null
0N/A if (authTime != null) {
0N/A result = result * 37 + authTime.hashCode();
0N/A }
0N/A
0N/A // startTime may be null
0N/A if (startTime != null) {
0N/A result = result * 37 + startTime.hashCode();
0N/A }
0N/A
0N/A // renewTill may be null
0N/A if (renewTill != null) {
0N/A result = result * 37 + renewTill.hashCode();
0N/A }
0N/A
0N/A // clientAddress may be null, the array's hashCode is 0
0N/A result = result * 37 + Arrays.hashCode(clientAddresses);
0N/A return result * 37 + Arrays.hashCode(flags);
0N/A }
0N/A
0N/A /**
0N/A * Compares the specified Object with this KerberosTicket for equality.
0N/A * Returns true if the given object is also a
0N/A * <code>KerberosTicket</code> and the two
0N/A * <code>KerberosTicket</code> instances are equivalent.
0N/A *
0N/A * @param other the Object to compare to
0N/A * @return true if the specified object is equal to this KerberosTicket,
0N/A * false otherwise. NOTE: Returns false if either of the KerberosTicket
0N/A * objects has been destroyed.
0N/A * @since 1.6
0N/A */
0N/A public boolean equals(Object other) {
0N/A
0N/A if (other == this)
0N/A return true;
0N/A
0N/A if (! (other instanceof KerberosTicket)) {
0N/A return false;
0N/A }
0N/A
0N/A KerberosTicket otherTicket = ((KerberosTicket) other);
0N/A if (isDestroyed() || otherTicket.isDestroyed()) {
0N/A return false;
0N/A }
0N/A
0N/A if (!Arrays.equals(getEncoded(), otherTicket.getEncoded()) ||
0N/A !endTime.equals(otherTicket.getEndTime()) ||
0N/A !server.equals(otherTicket.getServer()) ||
0N/A !client.equals(otherTicket.getClient()) ||
0N/A !sessionKey.equals(otherTicket.getSessionKey()) ||
0N/A !Arrays.equals(clientAddresses, otherTicket.getClientAddresses()) ||
0N/A !Arrays.equals(flags, otherTicket.getFlags())) {
0N/A return false;
0N/A }
0N/A
0N/A // authTime may be null
0N/A if (authTime == null) {
0N/A if (otherTicket.getAuthTime() != null)
0N/A return false;
0N/A } else {
0N/A if (!authTime.equals(otherTicket.getAuthTime()))
0N/A return false;
0N/A }
0N/A
0N/A // startTime may be null
0N/A if (startTime == null) {
0N/A if (otherTicket.getStartTime() != null)
0N/A return false;
0N/A } else {
0N/A if (!startTime.equals(otherTicket.getStartTime()))
0N/A return false;
0N/A }
0N/A
0N/A if (renewTill == null) {
0N/A if (otherTicket.getRenewTill() != null)
0N/A return false;
0N/A } else {
0N/A if (!renewTill.equals(otherTicket.getRenewTill()))
0N/A return false;
0N/A }
0N/A
0N/A return true;
0N/A }
265N/A
265N/A private void readObject(ObjectInputStream s)
265N/A throws IOException, ClassNotFoundException {
265N/A s.defaultReadObject();
265N/A if (sessionKey == null) {
265N/A throw new InvalidObjectException("Session key cannot be null");
265N/A }
265N/A try {
265N/A init(asn1Encoding, client, server, sessionKey,
265N/A flags, authTime, startTime, endTime,
265N/A renewTill, clientAddresses);
265N/A } catch (IllegalArgumentException iae) {
265N/A throw (InvalidObjectException)
265N/A new InvalidObjectException(iae.getMessage()).initCause(iae);
265N/A }
265N/A }
0N/A}