001/* KerberosTicket.java -- a kerberos ticket 002 Copyright (C) 2006 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package javax.security.auth.kerberos; 040 041import gnu.classpath.NotImplementedException; 042 043import java.io.Serializable; 044import java.net.InetAddress; 045import java.util.Date; 046 047import javax.crypto.SecretKey; 048import javax.security.auth.DestroyFailedException; 049import javax.security.auth.Destroyable; 050import javax.security.auth.RefreshFailedException; 051import javax.security.auth.Refreshable; 052 053/** 054 * This class represents a Kerberos ticket. See the Kerberos 055 * authentication RFC for more information: 056 * <a href="http://www.ietf.org/rfc/rfc1510.txt">RFC 1510</a>. 057 * 058 * @since 1.4 059 */ 060public class KerberosTicket 061 implements Destroyable, Serializable, Refreshable 062{ 063 private static final long serialVersionUID = 7395334370157380539L; 064 065 // Indices of the various flags. From the kerberos spec. 066 // We only list the ones we use. 067 private static final int FORWARDABLE = 1; 068 private static final int FORWARDED = 2; 069 private static final int PROXIABLE = 3; 070 private static final int PROXY = 4; 071 private static final int POSTDATED = 6; 072 private static final int RENEWABLE = 8; 073 private static final int INITIAL = 9; 074 private static final int NUM_FLAGS = 12; 075 076 private byte[] asn1Encoding; 077 private KeyImpl sessionKey; 078 private boolean[] flags; 079 private Date authTime; 080 private Date startTime; 081 private Date endTime; 082 private Date renewTill; 083 private KerberosPrincipal client; 084 private KerberosPrincipal server; 085 private InetAddress[] clientAddresses; 086 087 /** 088 * Create a new ticket given all the facts about it. 089 * 090 * Note that flags may be null or "short"; any flags not specified 091 * will be taken to be false. 092 * 093 * If the key is not renewable, then renewTill may be null. 094 * 095 * If authTime is null, then it is taken to be the same as startTime. 096 * 097 * If clientAddresses is null, then the ticket can be used anywhere. 098 * 099 * @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 "FIXME bob"; 338 } 339}