View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.kerberos.shared.messages.components;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  import java.text.ParseException;
26  
27  import javax.security.auth.kerberos.KerberosPrincipal;
28  
29  import org.apache.directory.server.kerberos.shared.KerberosConstants;
30  import org.apache.directory.server.kerberos.shared.KerberosUtils;
31  import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
32  import org.apache.directory.server.kerberos.shared.messages.value.AuthorizationData;
33  import org.apache.directory.server.kerberos.shared.messages.value.EncryptedData;
34  import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
35  import org.apache.directory.server.kerberos.shared.messages.value.HostAddresses;
36  import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime;
37  import org.apache.directory.server.kerberos.shared.messages.value.PrincipalName;
38  import org.apache.directory.server.kerberos.shared.messages.value.TransitedEncoding;
39  import org.apache.directory.server.kerberos.shared.messages.value.flags.TicketFlags;
40  import org.apache.directory.shared.asn1.AbstractAsn1Object;
41  import org.apache.directory.shared.asn1.ber.tlv.TLV;
42  import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
43  import org.apache.directory.shared.asn1.ber.tlv.Value;
44  import org.apache.directory.shared.asn1.codec.EncoderException;
45  import org.apache.directory.shared.ldap.util.StringTools;
46  import org.slf4j.Logger;
47  import org.slf4j.LoggerFactory;
48  
49  
50  /**
51   * Ticket message component as handed out by the ticket granting service.
52   * 
53   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
54   * @version $Rev: 642496 $, $Date: 2008-03-29 04:09:22 +0100 (Sa, 29 Mär 2008) $
55   */
56  public class Ticket extends AbstractAsn1Object
57  {
58      /** The logger */
59      private static final Logger LOG = LoggerFactory.getLogger( Ticket.class );
60  
61      /** Speedup for logs */
62      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
63      
64      /** Constant for the {@link Ticket} version number (5) */
65      public static final int TICKET_VNO = KerberosConstants.KERBEROS_V5;
66  
67      /** The Kerberos version number. Should be 5 */
68      private int tktvno;
69      
70      /** A storage for a byte array representation of the realm */
71      private byte[] realmBytes;
72      
73      /** The server principal name */
74      private PrincipalName sName;
75      
76      /** The server realm */
77      private String realm;
78      
79      /** The encoded part */
80      private EncryptedData encPart;
81      
82      /** The decoded ticket part */
83      private EncTicketPart encTicketPart;
84  
85      // Storage for computed lengths
86      private transient int tktvnoLength;
87      private transient int realmLength;
88      private transient int sNameLength;
89      private transient int encPartLength;
90      private transient int ticketSeqLength;
91      private transient int ticketLength;
92  
93      /**
94       * Creates a new instance of Ticket.
95       *
96       * @param serverPrincipal The server principal
97       * @param encPart The encoded part
98       */
99      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 }