/projects/jre-1.6.0/src/javax/security/auth/kerberos/KerberosTicket.java
https://gitlab.com/essere.lab.public/qualitas.class-corpus · Java · 731 lines · 336 code · 85 blank · 310 comment · 71 complexity · 89c2c74c6a3ce18d2b39fb34a241cae6 MD5 · raw file
- /*
- * %W% %E%
- *
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package javax.security.auth.kerberos;
- import java.io.*;
- import java.util.Date;
- import java.util.Arrays;
- import java.net.InetAddress;
- import javax.crypto.SecretKey;
- import javax.security.auth.Refreshable;
- import javax.security.auth.Destroyable;
- import javax.security.auth.RefreshFailedException;
- import javax.security.auth.DestroyFailedException;
- import sun.misc.HexDumpEncoder;
- import sun.security.krb5.EncryptionKey;
- import sun.security.krb5.Asn1Exception;
- import sun.security.util.*;
- /**
- * This class encapsulates a Kerberos ticket and associated
- * information as viewed from the client's point of view. It captures all
- * information that the Key Distribution Center (KDC) sends to the client
- * in the reply message KDC-REP defined in the Kerberos Protocol
- * Specification (<a href=http://www.ietf.org/rfc/rfc1510.txt>RFC 1510</a>).
- * <p>
- * All Kerberos JAAS login modules that authenticate a user to a KDC should
- * use this class. Where available, the login module might even read this
- * information from a ticket cache in the operating system instead of
- * directly communicating with the KDC. During the commit phase of the JAAS
- * authentication process, the JAAS login module should instantiate this
- * class and store the instance in the private credential set of a
- * {@link javax.security.auth.Subject Subject}.<p>
- *
- * It might be necessary for the application to be granted a
- * {@link javax.security.auth.PrivateCredentialPermission
- * PrivateCredentialPermission} if it needs to access a KerberosTicket
- * instance from a Subject. This permission is not needed when the
- * application depends on the default JGSS Kerberos mechanism to access the
- * KerberosTicket. In that case, however, the application will need an
- * appropriate
- * {@link javax.security.auth.kerberos.ServicePermission ServicePermission}.
- * <p>
- * Note that this class is applicable to both ticket granting tickets and
- * other regular service tickets. A ticket granting ticket is just a
- * special case of a more generalized service ticket.
- *
- * @see javax.security.auth.Subject
- * @see javax.security.auth.PrivateCredentialPermission
- * @see javax.security.auth.login.LoginContext
- * @see org.ietf.jgss.GSSCredential
- * @see org.ietf.jgss.GSSManager
- *
- * @author Mayank Upadhyay
- * @version %I%, %G%
- * @since 1.4
- */
- public class KerberosTicket implements Destroyable, Refreshable,
- java.io.Serializable {
- private static final long serialVersionUID = 7395334370157380539L;
- // XXX Make these flag indices public
- private static final int FORWARDABLE_TICKET_FLAG = 1;
- private static final int FORWARDED_TICKET_FLAG = 2;
- private static final int PROXIABLE_TICKET_FLAG = 3;
- private static final int PROXY_TICKET_FLAG = 4;
- private static final int POSTDATED_TICKET_FLAG = 6;
- private static final int RENEWABLE_TICKET_FLAG = 8;
- private static final int INITIAL_TICKET_FLAG = 9;
- private static final int NUM_FLAGS = 32;
- /**
- *
- * ASN.1 DER Encoding of the Ticket as defined in the
- * Kerberos Protocol Specification RFC1510.
- *
- * @serial
- */
- private byte[] asn1Encoding;
- /**
- *<code>KeyImpl</code> is serialized by writing out the ASN1 Encoded bytes
- * of the encryption key. The ASN1 encoding is defined in RFC1510 and as
- * follows:
- * <pre>
- * EncryptionKey ::= SEQUENCE {
- * keytype[0] INTEGER,
- * keyvalue[1] OCTET STRING
- * }
- * </pre>
- *
- * @serial
- */
- private KeyImpl sessionKey;
- /**
- *
- * Ticket Flags as defined in the Kerberos Protocol Specification RFC1510.
- *
- * @serial
- */
- private boolean[] flags;
- /**
- *
- * Time of initial authentication
- *
- * @serial
- */
- private Date authTime;
- /**
- *
- * Time after which the ticket is valid.
- * @serial
- */
- private Date startTime;
- /**
- *
- * Time after which the ticket will not be honored. (its expiration time).
- *
- * @serial
- */
- private Date endTime;
- /**
- *
- * For renewable Tickets it indicates the maximum endtime that may be
- * included in a renewal. It can be thought of as the absolute expiration
- * time for the ticket, including all renewals. This field may be null
- * for tickets that are not renewable.
- *
- * @serial
- */
- private Date renewTill;
- /**
- *
- * Client that owns the service ticket
- *
- * @serial
- */
- private KerberosPrincipal client;
- /**
- *
- * The service for which the ticket was issued.
- *
- * @serial
- */
- private KerberosPrincipal server;
-
- /**
- *
- * The addresses from where the ticket may be used by the client.
- * This field may be null when the ticket is usable from any address.
- *
- * @serial
- */
- private InetAddress[] clientAddresses;
- private transient boolean destroyed = false;
- /**
- * Constructs a KerberosTicket using credentials information that a
- * client either receives from a KDC or reads from a cache.
- *
- * @param asn1Encoding the ASN.1 encoding of the ticket as defined by
- * the Kerberos protocol specification.
- * @param client the client that owns this service
- * ticket
- * @param server the service that this ticket is for
- * @param sessionKey the raw bytes for the session key that must be
- * used to encrypt the authenticator that will be sent to the server
- * @param keyType the key type for the session key as defined by the
- * Kerberos protocol specification.
- * @param flags the ticket flags. Each element in this array indicates
- * the value for the corresponding bit in the ASN.1 BitString that
- * represents the ticket flags. If the number of elements in this array
- * is less than the number of flags used by the Kerberos protocol,
- * then the missing flags will be filled in with false.
- * @param authTime the time of initial authentication for the client
- * @param startTime the time after which the ticket will be valid. This
- * may be null in which case the value of authTime is treated as the
- * startTime.
- * @param endTime the time after which the ticket will no longer be
- * valid
- * @param renewTill an absolute expiration time for the ticket,
- * including all renewal that might be possible. This field may be null
- * for tickets that are not renewable.
- * @param clientAddresses the addresses from where the ticket may be
- * used by the client. This field may be null when the ticket is usable
- * from any address.
- */
- public KerberosTicket(byte[] asn1Encoding,
- KerberosPrincipal client,
- KerberosPrincipal server,
- byte[] sessionKey,
- int keyType,
- boolean[] flags,
- Date authTime,
- Date startTime,
- Date endTime,
- Date renewTill,
- InetAddress[] clientAddresses) {
-
- init(asn1Encoding, client, server, sessionKey, keyType, flags,
- authTime, startTime, endTime, renewTill, clientAddresses);
- }
-
- private void init(byte[] asn1Encoding,
- KerberosPrincipal client,
- KerberosPrincipal server,
- byte[] sessionKey,
- int keyType,
- boolean[] flags,
- Date authTime,
- Date startTime,
- Date endTime,
- Date renewTill,
- InetAddress[] clientAddresses) {
- if (asn1Encoding == null)
- throw new IllegalArgumentException("ASN.1 encoding of ticket"
- + " cannot be null");
- this.asn1Encoding = asn1Encoding.clone();
- if (client == null)
- throw new IllegalArgumentException("Client name in ticket"
- + " cannot be null");
- this.client = client;
- if (server == null)
- throw new IllegalArgumentException("Server name in ticket"
- + " cannot be null");
- this.server = server;
- if (sessionKey == null)
- throw new IllegalArgumentException("Session key for ticket"
- + " cannot be null");
- this.sessionKey = new KeyImpl(sessionKey, keyType);
- if (flags != null) {
- if (flags.length >= NUM_FLAGS)
- this.flags = (boolean[]) flags.clone();
- else {
- this.flags = new boolean[NUM_FLAGS];
- // Fill in whatever we have
- for (int i = 0; i < flags.length; i++)
- this.flags[i] = flags[i];
- }
- } else
- this.flags = new boolean[NUM_FLAGS];
- if (this.flags[RENEWABLE_TICKET_FLAG]) {
- if (renewTill == null)
- throw new IllegalArgumentException("The renewable period "
- + "end time cannot be null for renewable tickets.");
- this.renewTill = renewTill;
- }
- this.authTime = authTime;
- this.startTime = (startTime != null? startTime: authTime);
- if (endTime == null)
- throw new IllegalArgumentException("End time for ticket validity"
- + " cannot be null");
- this.endTime = endTime;
- if (clientAddresses != null)
- this.clientAddresses = (InetAddress[]) clientAddresses.clone();
- }
- /**
- * Returns the client principal associated with this ticket.
- *
- * @return the client principal.
- */
- public final KerberosPrincipal getClient() {
- return client;
- }
-
- /**
- * Returns the service principal associated with this ticket.
- *
- * @return the service principal.
- */
- public final KerberosPrincipal getServer() {
- return server;
- }
-
- /**
- * Returns the session key associated with this ticket.
- *
- * @return the session key.
- */
- public final SecretKey getSessionKey() {
- if (destroyed)
- throw new IllegalStateException("This ticket is no longer valid");
- return sessionKey;
- }
- /**
- * Returns the key type of the session key associated with this
- * ticket as defined by the Kerberos Protocol Specification.
- *
- * @return the key type of the session key associated with this
- * ticket.
- *
- * @see #getSessionKey()
- */
- public final int getSessionKeyType() {
- if (destroyed)
- throw new IllegalStateException("This ticket is no longer valid");
- return sessionKey.getKeyType();
- }
- /**
- * Determines if this ticket is forwardable.
- *
- * @return true if this ticket is forwardable, false if not.
- */
- public final boolean isForwardable() {
- return flags[FORWARDABLE_TICKET_FLAG];
- }
- /**
- * Determines if this ticket had been forwarded or was issued based on
- * authentication involving a forwarded ticket-granting ticket.
- *
- * @return true if this ticket had been forwarded or was issued based on
- * authentication involving a forwarded ticket-granting ticket,
- * false otherwise.
- */
- public final boolean isForwarded() {
- return flags[FORWARDED_TICKET_FLAG];
- }
- /**
- * Determines if this ticket is proxiable.
- *
- * @return true if this ticket is proxiable, false if not.
- */
- public final boolean isProxiable() {
- return flags[PROXIABLE_TICKET_FLAG];
- }
- /**
- * Determines is this ticket is a proxy-ticket.
- *
- * @return true if this ticket is a proxy-ticket, false if not.
- */
- public final boolean isProxy() {
- return flags[PROXY_TICKET_FLAG];
- }
- /**
- * Determines is this ticket is post-dated.
- *
- * @return true if this ticket is post-dated, false if not.
- */
- public final boolean isPostdated() {
- return flags[POSTDATED_TICKET_FLAG];
- }
- /**
- * Determines is this ticket is renewable. If so, the {@link #refresh()
- * refresh} method can be called, assuming the validity period for
- * renewing is not already over.
- *
- * @return true if this ticket is renewable, false if not.
- */
- public final boolean isRenewable() {
- return flags[RENEWABLE_TICKET_FLAG];
- }
- /**
- * Determines if this ticket was issued using the Kerberos AS-Exchange
- * protocol, and not issued based on some ticket-granting ticket.
- *
- * @return true if this ticket was issued using the Kerberos AS-Exchange
- * protocol, false if not.
- */
- public final boolean isInitial() {
- return flags[INITIAL_TICKET_FLAG];
- }
- /**
- * Returns the flags associated with this ticket. Each element in the
- * returned array indicates the value for the corresponding bit in the
- * ASN.1 BitString that represents the ticket flags.
- *
- * @return the flags associated with this ticket.
- */
- public final boolean[] getFlags() {
- return (flags == null? null: (boolean[]) flags.clone());
- }
- /**
- * Returns the time that the client was authenticated.
- *
- * @return the time that the client was authenticated
- * or null if not set.
- */
- public final java.util.Date getAuthTime() {
- return (authTime == null) ? null : new Date(authTime.getTime());
- }
- /**
- * Returns the start time for this ticket's validity period.
- *
- * @return the start time for this ticket's validity period
- * or null if not set.
- */
- public final java.util.Date getStartTime() {
- return (startTime == null) ? null : new Date(startTime.getTime());
- }
- /**
- * Returns the expiration time for this ticket's validity period.
- *
- * @return the expiration time for this ticket's validity period.
- */
- public final java.util.Date getEndTime() {
- return endTime;
- }
- /**
- * Returns the latest expiration time for this ticket, including all
- * renewals. This will return a null value for non-renewable tickets.
- *
- * @return the latest expiration time for this ticket.
- */
- public final java.util.Date getRenewTill() {
- return (renewTill == null) ? null: new Date(renewTill.getTime());
- }
-
- /**
- * Returns a list of addresses from where the ticket can be used.
- *
- * @return ths list of addresses or null, if the field was not
- * provided.
- */
- public final java.net.InetAddress[] getClientAddresses() {
- return (clientAddresses == null?
- null: (InetAddress[]) clientAddresses.clone());
- }
- /**
- * Returns an ASN.1 encoding of the entire ticket.
- *
- * @return an ASN.1 encoding of the entire ticket.
- */
- public final byte[] getEncoded() {
- if (destroyed)
- throw new IllegalStateException("This ticket is no longer valid");
- return (byte[]) asn1Encoding.clone();
- }
- /** Determines if this ticket is still current. */
- public boolean isCurrent() {
- return (System.currentTimeMillis() <= getEndTime().getTime());
- }
- /**
- * Extends the validity period of this ticket. The ticket will contain
- * a new session key if the refresh operation succeeds. The refresh
- * operation will fail if the ticket is not renewable or the latest
- * allowable renew time has passed. Any other error returned by the
- * KDC will also cause this method to fail.
- *
- * Note: This method is not synchronized with the the accessor
- * methods of this object. Hence callers need to be aware of multiple
- * threads that might access this and try to renew it at the same
- * time.
- *
- * @throws RefreshFailedException if the ticket is not renewable, or
- * the latest allowable renew time has passed, or the KDC returns some
- * error.
- *
- * @see #isRenewable()
- * @see #getRenewTill()
- */
- public void refresh() throws RefreshFailedException {
- if (destroyed)
- throw new RefreshFailedException("A destroyed ticket "
- + "cannot be renewd.");
- if (!isRenewable())
- throw new RefreshFailedException("This ticket is not renewable");
- if (System.currentTimeMillis() > getRenewTill().getTime())
- throw new RefreshFailedException("This ticket is past "
- + "its last renewal time.");
- Throwable e = null;
- sun.security.krb5.Credentials krb5Creds = null;
- try {
- krb5Creds = new sun.security.krb5.Credentials(asn1Encoding,
- client.toString(),
- server.toString(),
- sessionKey.getEncoded(),
- sessionKey.getKeyType(),
- flags,
- authTime,
- startTime,
- endTime,
- renewTill,
- clientAddresses);
- krb5Creds = krb5Creds.renew();
- } catch (sun.security.krb5.KrbException krbException) {
- e = krbException;
- } catch (java.io.IOException ioException) {
- e = ioException;
- }
- if (e != null) {
- RefreshFailedException rfException
- = new RefreshFailedException("Failed to renew Kerberos Ticket "
- + "for client " + client
- + " and server " + server
- + " - " + e.getMessage());
- rfException.initCause(e);
- throw rfException;
- }
- /*
- * In case multiple threads try to refresh it at the same time.
- */
- synchronized (this) {
- try {
- this.destroy();
- } catch (DestroyFailedException dfException) {
- // Squelch it since we don't care about the old ticket.
- }
- init(krb5Creds.getEncoded(),
- new KerberosPrincipal(krb5Creds.getClient().getName()),
- new KerberosPrincipal(krb5Creds.getServer().getName()),
- krb5Creds.getSessionKey().getBytes(),
- krb5Creds.getSessionKey().getEType(),
- krb5Creds.getFlags(),
- krb5Creds.getAuthTime(),
- krb5Creds.getStartTime(),
- krb5Creds.getEndTime(),
- krb5Creds.getRenewTill(),
- krb5Creds.getClientAddresses());
- destroyed = false;
- }
- }
- /**
- * Destroys the ticket and destroys any sensitive information stored in
- * it.
- */
- public void destroy() throws DestroyFailedException {
- if (!destroyed) {
- Arrays.fill(asn1Encoding, (byte) 0);
- client = null;
- server = null;
- sessionKey.destroy();
- flags = null;
- authTime = null;
- startTime = null;
- endTime = null;
- renewTill = null;
- clientAddresses = null;
- destroyed = true;
- }
- }
- /**
- * Determines if this ticket has been destroyed.
- */
- public boolean isDestroyed() {
- return destroyed;
- }
- public String toString() {
- if (destroyed)
- throw new IllegalStateException("This ticket is no longer valid");
- StringBuffer caddrBuf = new StringBuffer();
- if (clientAddresses != null) {
- for (int i = 0; i < clientAddresses.length; i++) {
- caddrBuf.append("clientAddresses[" + i + "] = " +
- clientAddresses[i].toString());
- }
- }
- return ("Ticket (hex) = " + "\n" +
- (new HexDumpEncoder()).encodeBuffer(asn1Encoding) + "\n" +
- "Client Principal = " + client.toString() + "\n" +
- "Server Principal = " + server.toString() + "\n" +
- "Session Key = " + sessionKey.toString() + "\n" +
- "Forwardable Ticket " + flags[FORWARDABLE_TICKET_FLAG] + "\n" +
- "Forwarded Ticket " + flags[FORWARDED_TICKET_FLAG] + "\n" +
- "Proxiable Ticket " + flags[PROXIABLE_TICKET_FLAG] + "\n" +
- "Proxy Ticket " + flags[PROXY_TICKET_FLAG] + "\n" +
- "Postdated Ticket " + flags[POSTDATED_TICKET_FLAG] + "\n" +
- "Renewable Ticket " + flags[RENEWABLE_TICKET_FLAG] + "\n" +
- "Initial Ticket " + flags[RENEWABLE_TICKET_FLAG] + "\n" +
- "Auth Time = " + String.valueOf(authTime) + "\n" +
- "Start Time = " + String.valueOf(startTime) + "\n" +
- "End Time = " + endTime.toString() + "\n" +
- "Renew Till = " + String.valueOf(renewTill) + "\n" +
- "Client Addresses " +
- (clientAddresses == null ? " Null " : caddrBuf.toString() +
- "\n"));
- }
- /**
- * Returns a hashcode for this KerberosTicket.
- *
- * @return a hashCode() for the <code>KerberosTicket</code>
- * @since 1.6
- */
- public int hashCode() {
- int result = 17;
- if (isDestroyed()) {
- return result;
- }
- result = result * 37 + Arrays.hashCode(getEncoded());
- result = result * 37 + endTime.hashCode();
- result = result * 37 + client.hashCode();
- result = result * 37 + server.hashCode();
- result = result * 37 + sessionKey.hashCode();
-
- // authTime may be null
- if (authTime != null) {
- result = result * 37 + authTime.hashCode();
- }
- // startTime may be null
- if (startTime != null) {
- result = result * 37 + startTime.hashCode();
- }
- // renewTill may be null
- if (renewTill != null) {
- result = result * 37 + renewTill.hashCode();
- }
- // clientAddress may be null, the array's hashCode is 0
- result = result * 37 + Arrays.hashCode(clientAddresses);
- return result * 37 + Arrays.hashCode(flags);
- }
- /**
- * Compares the specified Object with this KerberosTicket for equality.
- * Returns true if the given object is also a
- * <code>KerberosTicket</code> and the two
- * <code>KerberosTicket</code> instances are equivalent.
- *
- * @param other the Object to compare to
- * @return true if the specified object is equal to this KerberosTicket,
- * false otherwise. NOTE: Returns false if either of the KerberosTicket
- * objects has been destroyed.
- * @since 1.6
- */
- public boolean equals(Object other) {
- if (other == this)
- return true;
- if (! (other instanceof KerberosTicket)) {
- return false;
- }
-
- KerberosTicket otherTicket = ((KerberosTicket) other);
- if (isDestroyed() || otherTicket.isDestroyed()) {
- return false;
- }
- if (!Arrays.equals(getEncoded(), otherTicket.getEncoded()) ||
- !endTime.equals(otherTicket.getEndTime()) ||
- !server.equals(otherTicket.getServer()) ||
- !client.equals(otherTicket.getClient()) ||
- !sessionKey.equals(otherTicket.getSessionKey()) ||
- !Arrays.equals(clientAddresses, otherTicket.getClientAddresses()) ||
- !Arrays.equals(flags, otherTicket.getFlags())) {
- return false;
- }
- // authTime may be null
- if (authTime == null) {
- if (otherTicket.getAuthTime() != null)
- return false;
- } else {
- if (!authTime.equals(otherTicket.getAuthTime()))
- return false;
- }
- // startTime may be null
- if (startTime == null) {
- if (otherTicket.getStartTime() != null)
- return false;
- } else {
- if (!startTime.equals(otherTicket.getStartTime()))
- return false;
- }
- if (renewTill == null) {
- if (otherTicket.getRenewTill() != null)
- return false;
- } else {
- if (!renewTill.equals(otherTicket.getRenewTill()))
- return false;
- }
- return true;
- }
- }