001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.server.kerberos.shared.messages.components;
021
022
023 import java.nio.BufferOverflowException;
024 import java.nio.ByteBuffer;
025 import java.text.ParseException;
026
027 import javax.security.auth.kerberos.KerberosPrincipal;
028
029 import org.apache.directory.server.kerberos.shared.KerberosConstants;
030 import org.apache.directory.server.kerberos.shared.KerberosUtils;
031 import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
032 import org.apache.directory.server.kerberos.shared.messages.value.AuthorizationData;
033 import org.apache.directory.server.kerberos.shared.messages.value.EncryptedData;
034 import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
035 import org.apache.directory.server.kerberos.shared.messages.value.HostAddresses;
036 import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime;
037 import org.apache.directory.server.kerberos.shared.messages.value.PrincipalName;
038 import org.apache.directory.server.kerberos.shared.messages.value.TransitedEncoding;
039 import org.apache.directory.server.kerberos.shared.messages.value.flags.TicketFlags;
040 import org.apache.directory.shared.asn1.AbstractAsn1Object;
041 import org.apache.directory.shared.asn1.ber.tlv.TLV;
042 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
043 import org.apache.directory.shared.asn1.ber.tlv.Value;
044 import org.apache.directory.shared.asn1.codec.EncoderException;
045 import org.apache.directory.shared.ldap.util.StringTools;
046 import org.slf4j.Logger;
047 import org.slf4j.LoggerFactory;
048
049
050 /**
051 * Ticket message component as handed out by the ticket granting service.
052 *
053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
054 * @version $Rev: 642496 $, $Date: 2008-03-29 05:09:22 +0200 (Sat, 29 Mar 2008) $
055 */
056 public class Ticket extends AbstractAsn1Object
057 {
058 /** The logger */
059 private static final Logger LOG = LoggerFactory.getLogger( Ticket.class );
060
061 /** Speedup for logs */
062 private static final boolean IS_DEBUG = LOG.isDebugEnabled();
063
064 /** Constant for the {@link Ticket} version number (5) */
065 public static final int TICKET_VNO = KerberosConstants.KERBEROS_V5;
066
067 /** The Kerberos version number. Should be 5 */
068 private int tktvno;
069
070 /** A storage for a byte array representation of the realm */
071 private byte[] realmBytes;
072
073 /** The server principal name */
074 private PrincipalName sName;
075
076 /** The server realm */
077 private String realm;
078
079 /** The encoded part */
080 private EncryptedData encPart;
081
082 /** The decoded ticket part */
083 private EncTicketPart encTicketPart;
084
085 // Storage for computed lengths
086 private transient int tktvnoLength;
087 private transient int realmLength;
088 private transient int sNameLength;
089 private transient int encPartLength;
090 private transient int ticketSeqLength;
091 private transient int ticketLength;
092
093 /**
094 * Creates a new instance of Ticket.
095 *
096 * @param serverPrincipal The server principal
097 * @param encPart The encoded part
098 */
099 public Ticket( KerberosPrincipal serverPrincipal, EncryptedData encPart ) throws InvalidTicketException
100 {
101 this( TICKET_VNO, serverPrincipal, encPart );
102
103 setServerPrincipal( serverPrincipal );
104 }
105
106
107 /**
108 * Creates a new instance of Ticket.
109 */
110 public Ticket()
111 {
112 }
113
114
115 /**
116 * Creates a new instance of Ticket.
117 *
118 * @param tktvno The Kerberos version number
119 * @param serverPrincipal The server principal
120 * @param encPart The encoded part
121 */
122 public Ticket( int tktvno, KerberosPrincipal serverPrincipal, EncryptedData encPart ) throws InvalidTicketException
123 {
124 this.tktvno = tktvno;
125 this.encPart = encPart;
126 setServerPrincipal( serverPrincipal );
127 }
128
129
130 /**
131 * Sets the {@link EncTicketPart}.
132 *
133 * @param decryptedPart
134 */
135 public void setEncTicketPart( EncTicketPart decryptedPart )
136 {
137 encTicketPart = decryptedPart;
138 }
139
140
141 /**
142 * Returns the version number.
143 *
144 * @return The version number.
145 */
146 public int getTktVno()
147 {
148 return tktvno;
149 }
150
151
152 /**
153 * Set the ticket version number
154 * @param tktvno the ticket version number
155 */
156 public void setTktVno( int tktvno )
157 {
158 this.tktvno = tktvno;
159 }
160
161
162 /**
163 * Returns the server {@link PrincipalName}.
164 *
165 * @return The server {@link PrincipalName}.
166 */
167 public PrincipalName getSName()
168 {
169 return sName;
170 }
171
172
173 /**
174 * Returns the server {@link KerberosPrincipal}.
175 *
176 * @return The server {@link KerberosPrincipal}.
177 */
178 public KerberosPrincipal getServerPrincipal()
179 {
180 return KerberosUtils.getKerberosPrincipal( sName, realm );
181 }
182
183
184 /**
185 * Set the server principalName
186 * @param sName the server principalName
187 */
188 public void setSName( PrincipalName sName )
189 {
190 this.sName = sName;
191 }
192
193
194 /**
195 * Set the server KerberosPrincipal
196 * @param serverPrincipal the server KerberosPrincipal
197 */
198 public void setServerPrincipal( KerberosPrincipal serverPrincipal ) throws InvalidTicketException
199 {
200 try
201 {
202 sName = new PrincipalName( serverPrincipal.getName(), serverPrincipal.getNameType() );
203 realm = serverPrincipal.getRealm();
204 }
205 catch ( ParseException pe )
206 {
207 LOG.error( "Cannot create a ticket for the {} KerberosPrincipal, error : {}", serverPrincipal, pe.getMessage() );
208 throw new InvalidTicketException( ErrorType.KRB_ERR_GENERIC, "Cannot create a ticket : " + pe.getMessage() );
209 }
210 }
211
212
213 /**
214 * Returns the server realm.
215 *
216 * @return The server realm.
217 */
218 public String getRealm()
219 {
220 return realm;
221 }
222
223
224 /**
225 * Set the server realm
226 * @param realm the server realm
227 */
228 public void setRealm( String realm )
229 {
230 this.realm = realm;
231 }
232
233
234 /**
235 * Returns the {@link EncryptedData}.
236 *
237 * @return The {@link EncryptedData}.
238 */
239 public EncryptedData getEncPart()
240 {
241 return encPart;
242 }
243
244
245 /**
246 * Set the encrypted ticket part
247 * @param encPart the encrypted ticket part
248 */
249 public void setEncPart( EncryptedData encPart )
250 {
251 this.encPart = encPart;
252 }
253
254
255 /**
256 * Returns the {@link EncTicketPart}.
257 *
258 * @return The {@link EncTicketPart}.
259 */
260 public EncTicketPart getEncTicketPart()
261 {
262 return encTicketPart;
263 }
264
265
266 /**
267 * Returns the {@link AuthorizationData}.
268 *
269 * @return The {@link AuthorizationData}.
270 *
271 public AuthorizationData getAuthorizationData()
272 {
273 return encTicketPart.getAuthorizationData();
274 }
275 */
276
277 /**
278 * Returns the auth {@link KerberosTime}.
279 *
280 * @return The auth {@link KerberosTime}.
281 *
282 public KerberosTime getAuthTime()
283 {
284 return encTicketPart.getAuthTime();
285 }
286 */
287
288 /**
289 * Returns the client {@link HostAddresses}.
290 *
291 * @return The client {@link HostAddresses}.
292 *
293 public HostAddresses getClientAddresses()
294 {
295 return encTicketPart.getClientAddresses();
296 }
297 */
298
299 /**
300 * Returns the client {@link KerberosPrincipal}.
301 *
302 * @return The client {@link KerberosPrincipal}.
303 *
304 public KerberosPrincipal getClientPrincipal()
305 {
306 return encTicketPart.getClientPrincipal();
307 }
308 */
309
310 /**
311 * Returns the client {@link PrincipalName}.
312 *
313 * @return The client {@link PrincipalName}.
314 *
315 public PrincipalName getClientPrincipalName()
316 {
317 return encTicketPart.getClientPrincipalName();
318 }
319 */
320
321 /**
322 * Returns the client realm.
323 *
324 * @return The client realm.
325 *
326 public String getClientRealm()
327 {
328 return encTicketPart.getClientRealm();
329 }
330 */
331
332 /**
333 * Returns the end {@link KerberosTime}.
334 *
335 * @return The end {@link KerberosTime}.
336 *
337 public KerberosTime getEndTime()
338 {
339 return encTicketPart.getEndTime();
340 }
341 */
342
343 /**
344 * Returns the {@link TicketFlags}.
345 *
346 * @return The {@link TicketFlags}.
347 *
348 public TicketFlags getFlags()
349 {
350 return encTicketPart.getFlags();
351 }
352 */
353
354 /**
355 * Returns the integer value for the {@link TicketFlags}.
356 *
357 * @return The {@link TicketFlags}.
358 *
359 public int getFlagsIntValue()
360 {
361 return encTicketPart.getFlags().getIntValue();
362 }
363 */
364
365 /**
366 * Returns the renew till {@link KerberosTime}.
367 *
368 * @return The renew till {@link KerberosTime}.
369 *
370 public KerberosTime getRenewTill()
371 {
372 return encTicketPart.getRenewTill();
373 }
374 */
375
376 /**
377 * Returns the session {@link EncryptionKey}.
378 *
379 * @return The session {@link EncryptionKey}.
380 *
381 public EncryptionKey getSessionKey()
382 {
383 return encTicketPart.getSessionKey();
384 }
385 */
386
387 /**
388 * Returns the start {@link KerberosTime}.
389 *
390 * @return The start {@link KerberosTime}.
391 *
392 public KerberosTime getStartTime()
393 {
394 return encTicketPart.getStartTime();
395 }
396 */
397
398 /**
399 * Returns the {@link TransitedEncoding}.
400 *
401 * @return The {@link TransitedEncoding}.
402 *
403 public TransitedEncoding getTransitedEncoding()
404 {
405 return encTicketPart.getTransitedEncoding();
406 }
407 */
408
409 /**
410 * Returns the flag at the given index.
411 *
412 * @param flag
413 * @return true if the flag at the given index is set.
414 *
415 public boolean getFlag( int flag )
416 {
417 return encTicketPart.getFlags().isFlagSet( flag );
418 }
419 */
420
421 /**
422 * Compute the Ticket length
423 *
424 * Ticket :
425 *
426 * 0x61 L1 Ticket [APPLICATION 1]
427 * |
428 * +--> 0x30 L2 Ticket SEQUENCE
429 * |
430 * +--> 0xA0 L3 tkt-vno tag
431 * | |
432 * | +--> 0x02 L3-1 tkt-vno (int, 5)
433 * |
434 * +--> 0xA1 L4 realm tag
435 * | |
436 * | +--> 0x1B L4-1 realm (KerberosString)
437 * |
438 * +--> 0xA2 L5 sname (PrincipalName)
439 * |
440 * +--> 0xA3 L6 enc-part (EncryptedData)
441 */
442 public int computeLength()
443 {
444 // Compute the Ticket version length.
445 tktvnoLength = 1 + TLV.getNbBytes( tktvno ) + Value.getNbBytes( tktvno );
446
447 // Compute the Ticket realm length.
448 realmBytes = StringTools.getBytesUtf8( realm );
449 realmLength = 1 + TLV.getNbBytes( realmBytes.length ) + realmBytes.length;
450
451 // Compute the principal length
452 sNameLength = sName.computeLength();
453
454 // Compute the encrypted data
455 encPartLength = encPart.computeLength();
456
457 // Compute the sequence size
458 ticketSeqLength =
459 1 + TLV.getNbBytes( tktvnoLength ) + tktvnoLength +
460 1 + TLV.getNbBytes( realmLength ) + realmLength +
461 1 + TLV.getNbBytes( sNameLength ) + sNameLength +
462 1 + TLV.getNbBytes( encPartLength ) + encPartLength;
463
464 // compute the global size
465 ticketLength = 1 + TLV.getNbBytes( ticketSeqLength ) + ticketSeqLength;
466
467 return 1 + TLV.getNbBytes( ticketLength ) + ticketLength;
468 }
469
470 /**
471 * Encode the Ticket message to a PDU.
472 *
473 * Ticket :
474 *
475 * 0x61 LL
476 * 0x30 LL
477 * 0xA0 LL tktvno
478 * 0xA1 LL realm
479 * 0xA2 LL
480 * sname (PrincipalName)
481 * 0xA3 LL
482 * enc-part (EncryptedData)
483 *
484 * @param buffer The buffer where to put the PDU. It should have been allocated
485 * before, with the right size.
486 * @return The constructed PDU.
487 */
488 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
489 {
490 if ( buffer == null )
491 {
492 buffer = ByteBuffer.allocate( computeLength() );
493 }
494
495 try
496 {
497 // The Ticket APPLICATION Tag
498 buffer.put( (byte)0x61 );
499 buffer.put( TLV.getBytes( ticketLength ) );
500
501 // The Ticket SEQUENCE Tag
502 buffer.put( UniversalTag.SEQUENCE_TAG );
503 buffer.put( TLV.getBytes( ticketSeqLength ) );
504
505 // The tkt-vno Tag and value
506 buffer.put( ( byte ) 0xA0 );
507 buffer.put( TLV.getBytes( tktvnoLength ) );
508 Value.encode( buffer, tktvno );
509
510 // The realm Tag and value
511 buffer.put( ( byte ) 0xA1 );
512 buffer.put( TLV.getBytes( realmLength ) );
513 buffer.put( UniversalTag.GENERALIZED_STRING_TAG );
514 buffer.put( TLV.getBytes( realmBytes.length ) );
515 buffer.put( realmBytes );
516
517 // The sname Tag and value
518 buffer.put( ( byte ) 0xA2 );
519 buffer.put( TLV.getBytes( sNameLength ) );
520 sName.encode( buffer );
521
522 // The encPartLength Tag and value
523 buffer.put( ( byte ) 0xA3 );
524 buffer.put( TLV.getBytes( encPartLength ) );
525 encPart.encode( buffer );
526 }
527 catch ( BufferOverflowException boe )
528 {
529 LOG.error( "Cannot encode the Ticket object, the PDU size is {} when only {} bytes has been allocated", 1
530 + TLV.getNbBytes( ticketLength ) + ticketLength, buffer.capacity() );
531 throw new EncoderException( "The PDU buffer size is too small !" );
532 }
533
534 if ( IS_DEBUG )
535 {
536 LOG.debug( "Ticket encoding : {}", StringTools.dumpBytes( buffer.array() ) );
537 LOG.debug( "Ticket initial value : {}", toString() );
538 }
539
540 return buffer;
541 }
542 }