Source for javax.security.auth.kerberos.KerberosTicket

   1: /* KerberosTicket.java -- a kerberos ticket
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.security.auth.kerberos;
  40: 
  41: import gnu.classpath.NotImplementedException;
  42: 
  43: import java.io.Serializable;
  44: import java.net.InetAddress;
  45: import java.util.Date;
  46: 
  47: import javax.crypto.SecretKey;
  48: import javax.security.auth.DestroyFailedException;
  49: import javax.security.auth.Destroyable;
  50: import javax.security.auth.RefreshFailedException;
  51: import javax.security.auth.Refreshable;
  52: 
  53: /**
  54:  * This class represents a Kerberos ticket.  See the Kerberos
  55:  * authentication RFC for more information:
  56:  * <a href="http://www.ietf.org/rfc/rfc1510.txt">RFC 1510</a>.
  57:  *
  58:  * @since 1.4
  59:  */
  60: public class KerberosTicket
  61:     implements Destroyable, Serializable, Refreshable
  62: {
  63:   private static final long serialVersionUID = 7395334370157380539L;
  64: 
  65:   // Indices of the various flags.  From the kerberos spec.
  66:   // We only list the ones we use.
  67:   private static final int FORWARDABLE = 1;
  68:   private static final int FORWARDED = 2;
  69:   private static final int PROXIABLE = 3;
  70:   private static final int PROXY = 4;
  71:   private static final int POSTDATED = 6;
  72:   private static final int RENEWABLE = 8;
  73:   private static final int INITIAL = 9;
  74:   private static final int NUM_FLAGS = 12;
  75: 
  76:   private byte[] asn1Encoding;
  77:   private KeyImpl sessionKey;
  78:   private boolean[] flags;
  79:   private Date authTime;
  80:   private Date startTime;
  81:   private Date endTime;
  82:   private Date renewTill;
  83:   private KerberosPrincipal client;
  84:   private KerberosPrincipal server;
  85:   private InetAddress[] clientAddresses;
  86: 
  87:   /**
  88:    * Create a new ticket given all the facts about it.
  89:    *
  90:    * Note that flags may be null or "short"; any flags not specified
  91:    * will be taken to be false.
  92:    *
  93:    * If the key is not renewable, then renewTill may be null.
  94:    *
  95:    * If authTime is null, then it is taken to be the same as startTime.
  96:    *
  97:    * If clientAddresses is null, then the ticket can be used anywhere.
  98:    *
  99:    * @param asn1Encoding the contents of the ticket, as ASN1
 100:    * @param client the client principal
 101:    * @param server the server principal
 102:    * @param key the contents of the session key
 103:    * @param type the type of the key
 104:    * @param flags an array of flags, as specified by the RFC
 105:    * @param authTime when the client was authenticated
 106:    * @param startTime starting time at which the ticket is valid
 107:    * @param endTime ending time, after which the ticket is invalid
 108:    * @param renewTill for a rewewable ticket, the time before which it must
 109:    * be renewed
 110:    * @param clientAddresses a possibly-null array of addresses where this
 111:    * ticket may be used
 112:    */
 113:   public KerberosTicket(byte[] asn1Encoding, KerberosPrincipal client,
 114:                         KerberosPrincipal server, byte[] key, int type,
 115:                         boolean[] flags, Date authTime, Date startTime,
 116:                         Date endTime, Date renewTill,
 117:                         InetAddress[] clientAddresses)
 118:   {
 119:     this.asn1Encoding = (byte[]) asn1Encoding.clone();
 120:     this.sessionKey = new KeyImpl(key, type);
 121:     this.flags = new boolean[NUM_FLAGS];
 122:     if (flags != null)
 123:       System.arraycopy(flags, 0, this.flags, 0,
 124:                        Math.min(flags.length, NUM_FLAGS));
 125:     this.flags = (boolean[]) flags.clone();
 126:     this.authTime = (Date) authTime.clone();
 127:     this.startTime = (Date) ((startTime == null)
 128:                               ? authTime : startTime).clone();
 129:     this.endTime = (Date) endTime.clone();
 130:     this.renewTill = (Date) renewTill.clone();
 131:     this.client = client;
 132:     this.server = server;
 133:     this.clientAddresses = (clientAddresses == null
 134:                             ? null
 135:                             : (InetAddress[]) clientAddresses.clone());
 136:   }
 137: 
 138:   /**
 139:    * Destroy this ticket.  This discards secret information.  After this
 140:    * method is called, other methods will throw IllegalStateException.
 141:    */
 142:   public void destroy() throws DestroyFailedException
 143:   {
 144:     if (sessionKey == null)
 145:       throw new DestroyFailedException("already destroyed");
 146:     sessionKey = null;
 147:     asn1Encoding = null;
 148:   }
 149: 
 150:   /**
 151:    * Return true if this ticket has been destroyed.
 152:    */
 153:   public boolean isDestroyed()
 154:   {
 155:     return sessionKey == null;
 156:   }
 157: 
 158:   /**
 159:    * Return true if the ticket is currently valid.  This is true if
 160:    * the system time is between the ticket's start and end times.
 161:    */
 162:   public boolean isCurrent()
 163:   {
 164:     long now = System.currentTimeMillis();
 165:     return startTime.getTime() <= now && now <= endTime.getTime();
 166:   }
 167: 
 168:   /**
 169:    * If the ticket is renewable, and the renewal time has not yet elapsed,
 170:    * attempt to renew the ticket.
 171:    * @throws RefreshFailedException if the renewal fails for any reason
 172:    */
 173:   public void refresh() throws RefreshFailedException, NotImplementedException
 174:   {
 175:     if (! isRenewable())
 176:       throw new RefreshFailedException("not renewable");
 177:     if (renewTill != null
 178:         && System.currentTimeMillis() >= renewTill.getTime())
 179:       throw new RefreshFailedException("renewal time elapsed");
 180:     // FIXME: must contact the KDC.
 181:     // Use the java.security.krb5.kdc property...
 182:     throw new RefreshFailedException("not implemented");
 183:   }
 184: 
 185:   /**
 186:    * Return the client principal for this ticket.
 187:    */
 188:   public final KerberosPrincipal getClient()
 189:   {
 190:     return client;
 191:   }
 192: 
 193:   /**
 194:    * Return the server principal for this ticket.
 195:    */
 196:   public final KerberosPrincipal getServer()
 197:   {
 198:     return server;
 199:   }
 200: 
 201:   /**
 202:    * Return true if this ticket is forwardable.
 203:    */
 204:   public final boolean isForwardable()
 205:   {
 206:     return flags[FORWARDABLE];
 207:   }
 208: 
 209:   /**
 210:    * Return true if this ticket has been forwarded.
 211:    */
 212:   public final boolean isForwarded()
 213:   {
 214:     return flags[FORWARDED];
 215:   }
 216: 
 217:   /**
 218:    * Return true if this ticket is proxiable.
 219:    */
 220:   public final boolean isProxiable()
 221:   {
 222:     return flags[PROXIABLE];
 223:   }
 224: 
 225:   /**
 226:    * Return true if this ticket is a proxy ticket.
 227:    */
 228:   public final boolean isProxy()
 229:   {
 230:     return flags[PROXY];
 231:   }
 232: 
 233:   /**
 234:    * Return true if this ticket was post-dated.
 235:    */
 236:   public final boolean isPostdated()
 237:   {
 238:     return flags[POSTDATED];
 239:   }
 240: 
 241:   /**
 242:    * Return true if this ticket is renewable.
 243:    */
 244:   public final boolean isRenewable()
 245:   {
 246:     return flags[RENEWABLE];
 247:   }
 248: 
 249:   /**
 250:    * Return true if this ticket was granted by an application
 251:    * server, and not via a ticket-granting ticket.
 252:    */
 253:   public final boolean isInitial()
 254:   {
 255:     return flags[INITIAL];
 256:   }
 257: 
 258:   /**
 259:    * Return the flags for this ticket as a boolean array.
 260:    * See the RFC to understand what the different entries mean.
 261:    */
 262:   public final boolean[] getFlags()
 263:   {
 264:     return (boolean[]) flags.clone();
 265:   }
 266: 
 267:   /**
 268:    * Return the authentication time for this ticket.
 269:    */
 270:   public final Date getAuthTime()
 271:   {
 272:     return (Date) authTime.clone();
 273:   }
 274: 
 275:   /**
 276:    * Return the start time for this ticket.
 277:    */
 278:   public final Date getStartTime()
 279:   {
 280:     return (Date) startTime.clone();
 281:   }
 282: 
 283:   /**
 284:    * Return the end time for this ticket.
 285:    */
 286:   public final Date getEndTime()
 287:   {
 288:     return (Date) endTime.clone();
 289:   }
 290: 
 291:   /**
 292:    * Return the renewal time for this ticket.  For a non-renewable
 293:    * ticket, this will return null.
 294:    */
 295:   public final Date getRenewTill()
 296:   {
 297:     return flags[RENEWABLE] ? ((Date) renewTill.clone()) : null;
 298:   }
 299: 
 300:   /**
 301:    * Return the allowable client addresses for this ticket.  This will
 302:    * return null if the ticket can be used anywhere.
 303:    */
 304:   public final InetAddress[] getClientAddresses()
 305:   {
 306:     return (clientAddresses == null
 307:             ? null
 308:             : (InetAddress[]) clientAddresses.clone());
 309:   }
 310: 
 311:   /**
 312:    * Return the encoded form of this ticket.
 313:    */
 314:   public final byte[] getEncoded()
 315:   {
 316:     checkDestroyed();
 317:     return (byte[]) sessionKey.key.clone();
 318:   }
 319: 
 320:   /**
 321:    * Return the secret key associated with this ticket.
 322:    */
 323:   public final SecretKey getSessionKey()
 324:   {
 325:     checkDestroyed();
 326:     return sessionKey;
 327:   }
 328: 
 329:   private void checkDestroyed()
 330:   {
 331:     if (sessionKey == null)
 332:       throw new IllegalStateException("key is destroyed");
 333:   }
 334: 
 335:   public String toString()
 336:   {
 337:     return getClass().getName() +
 338:       "[client=" + client +
 339:       ",server=" + server +
 340:       ",sessionKey=" + sessionKey +
 341:       ",flags=" + flags +
 342:       ",authTime=" + authTime +
 343:       ",startTime= " + startTime +
 344:       ",endTime=" + endTime +
 345:       ",renewTill=" + renewTill +
 346:       ",clientAddresses=" + clientAddresses +
 347:       "]";
 348:   }
 349: 
 350:   /**
 351:    * <p>
 352:    * Returns the type of the session key in accordance with
 353:    * RFC1510.  This usually corresponds to the encryption
 354:    * algorithm used by the key, though more than one algorithm
 355:    * may use the same key type (e.g. DES with different checksum
 356:    * mechanisms and chaining modes). Negative values are reserved
 357:    * for local use.  Non-negative values are for officially assigned
 358:    * type fields.  The RFC defines:
 359:    * </p>
 360:    * <ul>
 361:    * <li>0 &mdash; null</li>
 362:    * <li>1 &mdash; DES (in CBC mode with either MD4 or MD5 checksums)</li>
 363:    * </ul>
 364:    *
 365:    * @return the type of session key used by this ticket.
 366:    */
 367:   public final int getSessionKeyType()
 368:   {
 369:     return sessionKey.type;
 370:   }
 371: 
 372: }