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.shared.kerberos.messages;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  
26  import org.apache.directory.api.asn1.EncoderException;
27  import org.apache.directory.api.asn1.ber.tlv.BerValue;
28  import org.apache.directory.api.asn1.ber.tlv.TLV;
29  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
30  import org.apache.directory.api.util.Strings;
31  import org.apache.directory.server.i18n.I18n;
32  import org.apache.directory.shared.kerberos.KerberosConstants;
33  import org.apache.directory.shared.kerberos.KerberosMessageType;
34  import org.apache.directory.shared.kerberos.components.EncTicketPart;
35  import org.apache.directory.shared.kerberos.components.EncryptedData;
36  import org.apache.directory.shared.kerberos.components.PrincipalName;
37  import org.apache.directory.shared.kerberos.exceptions.InvalidTicketException;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  
42  /**
43   * Ticket message component as handed out by the ticket granting service. It will store
44   * the object described by the ASN.1 grammar :
45   * <pre>
46   * Ticket          ::= [APPLICATION 1] SEQUENCE {
47   *         tkt-vno         [0] INTEGER (5),
48   *         realm           [1] Realm,
49   *         sname           [2] &lt;PrincipalName&gt;,
50   *         enc-part        [3] &lt;EncryptedData&gt; -- EncTicketPart
51   * }
52   * </pre>
53   * 
54   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
55   */
56  public class Ticket extends KerberosMessage
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      /** A storage for a byte array representation of the realm */
68      private byte[] realmBytes;
69  
70      /** The server principal name */
71      private PrincipalName sName;
72  
73      /** The server realm */
74      private String realm;
75  
76      /** The encoded part */
77      private EncryptedData encPart;
78  
79      /** The encoded ticket part, stored in its original form (not encoded) */
80      private EncTicketPart encTicketPart;
81  
82      // Storage for computed lengths
83      private int tktvnoLength;
84      private int realmLength;
85      private int sNameLength;
86      private int encPartLength;
87      private int ticketSeqLength;
88      private int ticketLength;
89  
90  
91      /**
92       * Creates a new instance of Ticket.
93       *
94       * @param sName The server principal
95       * @param encPart The encoded part
96       */
97      public Ticket( PrincipalName sName, EncryptedData encPart ) throws InvalidTicketException
98      {
99          this( TICKET_VNO, sName, encPart );
100 
101         setSName( sName );
102     }
103 
104 
105     /**
106      * Creates a new instance of Ticket.
107      */
108     public Ticket()
109     {
110         super( KerberosMessageType.TICKET );
111     }
112 
113 
114     /**
115      * Creates a new instance of Ticket.
116      *
117      * @param tktvno The Kerberos version number
118      * @param sName The server principal
119      * @param encPart The encoded part
120      */
121     public Ticket( int tktvno, PrincipalName sName, EncryptedData encPart )
122     {
123         super( tktvno, KerberosMessageType.TICKET );
124         this.encPart = encPart;
125         setSName( sName );
126     }
127 
128 
129     /**
130      * Returns the {@link EncryptedData}.
131      *
132      * @return The {@link EncryptedData}.
133      */
134     public EncryptedData getEncPart()
135     {
136         return encPart;
137     }
138 
139 
140     /**
141      * Set the encrypted ticket part
142      * @param encPart the encrypted ticket part
143      */
144     public void setEncPart( EncryptedData encPart )
145     {
146         this.encPart = encPart;
147     }
148 
149 
150     /**
151      * Returns the server realm.
152      *
153      * @return The server realm.
154      */
155     public String getRealm()
156     {
157         return realm;
158     }
159 
160 
161     /**
162      * Set the server realm
163      * @param realm the server realm
164      */
165     public void setRealm( String realm )
166     {
167         this.realm = realm;
168     }
169 
170 
171     /**
172      * Returns the server {@link PrincipalName}.
173      *
174      * @return The server {@link PrincipalName}.
175      */
176     public PrincipalName getSName()
177     {
178         return sName;
179     }
180 
181 
182     /**
183      * Set the server principalName
184      * @param sName the server principalName
185      */
186     public void setSName( PrincipalName sName )
187     {
188         this.sName = sName;
189     }
190 
191 
192     /**
193      * Gets the Ticket Version number
194      * @return The ticket version number
195      */
196     public int getTktVno()
197     {
198         return getProtocolVersionNumber();
199     }
200 
201 
202     /**
203      * Sets the Ticket Version number
204      * @param tktVno The new version number
205      */
206     public void setTktVno( int tktVno )
207     {
208         setProtocolVersionNumber( tktVno );
209     }
210 
211 
212     /**
213      * @return the encTicketPart
214      */
215     public EncTicketPart getEncTicketPart()
216     {
217         return encTicketPart;
218     }
219 
220 
221     /**
222      * @param encTicketPart the encTicketPart to set
223      */
224     public void setEncTicketPart( EncTicketPart encTicketPart )
225     {
226         this.encTicketPart = encTicketPart;
227     }
228 
229 
230     /**
231      * Compute the Ticket length
232      * <pre>
233      * Ticket :
234      * 
235      * 0x61 L1 Ticket [APPLICATION 1]
236      *  |
237      *  +--&gt; 0x30 L2 Ticket SEQUENCE
238      *        |
239      *        +--&gt; 0xA0 L3 tkt-vno tag
240      *        |     |
241      *        |     +--&gt; 0x02 L3-1 tkt-vno (int, 5)
242      *        |
243      *        +--&gt; 0xA1 L4 realm tag
244      *        |     |
245      *        |     +--&gt; 0x1B L4-1 realm (KerberosString)
246      *        |
247      *        +--&gt; 0xA2 L5 sname (PrincipalName)
248      *        |
249      *        +--&gt; 0xA3 L6 enc-part (EncryptedData)
250      * </pre>
251      */
252     public int computeLength()
253     {
254         // Compute the Ticket version length.
255         tktvnoLength = 1 + 1 + BerValue.getNbBytes( getProtocolVersionNumber() );
256 
257         // Compute the Ticket realm length.
258         realmBytes = Strings.getBytesUtf8( realm );
259         realmLength = 1 + TLV.getNbBytes( realmBytes.length ) + realmBytes.length;
260 
261         // Compute the principal length
262         sNameLength = sName.computeLength();
263 
264         // Compute the encrypted data
265         encPartLength = encPart.computeLength();
266 
267         // Compute the sequence size
268         ticketSeqLength =
269             1 + TLV.getNbBytes( tktvnoLength ) + tktvnoLength +
270                 1 + TLV.getNbBytes( realmLength ) + realmLength +
271                 1 + TLV.getNbBytes( sNameLength ) + sNameLength +
272                 1 + TLV.getNbBytes( encPartLength ) + encPartLength;
273 
274         // compute the global size
275         ticketLength = 1 + TLV.getNbBytes( ticketSeqLength ) + ticketSeqLength;
276 
277         return 1 + TLV.getNbBytes( ticketLength ) + ticketLength;
278     }
279 
280 
281     /**
282      * Encode the Ticket message to a PDU. 
283      * <pre>
284      * Ticket :
285      * 
286      * 0x61 LL
287      *   0x30 LL
288      *     0xA0 LL tktvno 
289      *     0xA1 LL realm
290      *     0xA2 LL
291      *       sname (PrincipalName)
292      *     0xA3 LL
293      *       enc-part (EncryptedData)
294      * </pre>
295      * @return The constructed PDU.
296      */
297     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
298     {
299         if ( buffer == null )
300         {
301             buffer = ByteBuffer.allocate( computeLength() );
302         }
303 
304         try
305         {
306             // The Ticket APPLICATION Tag
307             buffer.put( ( byte ) KerberosConstants.TICKET_TAG );
308             buffer.put( TLV.getBytes( ticketLength ) );
309 
310             // The Ticket SEQUENCE Tag
311             buffer.put( UniversalTag.SEQUENCE.getValue() );
312             buffer.put( TLV.getBytes( ticketSeqLength ) );
313 
314             // The tkt-vno Tag and value
315             buffer.put( ( byte ) KerberosConstants.TICKET_TKT_VNO_TAG );
316             buffer.put( TLV.getBytes( tktvnoLength ) );
317             BerValue.encode( buffer, getProtocolVersionNumber() );
318 
319             // The realm Tag and value
320             buffer.put( ( byte ) KerberosConstants.TICKET_REALM_TAG );
321             buffer.put( TLV.getBytes( realmLength ) );
322             buffer.put( UniversalTag.GENERAL_STRING.getValue() );
323             buffer.put( TLV.getBytes( realmBytes.length ) );
324             buffer.put( realmBytes );
325 
326             // The sname Tag and value
327             buffer.put( ( byte ) KerberosConstants.TICKET_SNAME_TAG );
328             buffer.put( TLV.getBytes( sNameLength ) );
329             sName.encode( buffer );
330 
331             // The encPartLength Tag and value
332             buffer.put( ( byte ) KerberosConstants.TICKET_ENC_PART_TAG );
333             buffer.put( TLV.getBytes( encPartLength ) );
334             encPart.encode( buffer );
335         }
336         catch ( BufferOverflowException boe )
337         {
338             LOG.error( I18n.err( I18n.ERR_137, 1 + TLV.getNbBytes( ticketLength ) + ticketLength,
339                 buffer.capacity() ) );
340             throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
341         }
342 
343         if ( IS_DEBUG )
344         {
345             LOG.debug( "Ticket encoding : {}", Strings.dumpBytes( buffer.array() ) );
346             LOG.debug( "Ticket initial value : {}", this );
347         }
348 
349         return buffer;
350     }
351 
352 
353     /**
354      * {@inheritDoc}
355      */
356     @Override
357     public int hashCode()
358     {
359         final int prime = 31;
360         int result = 1;
361         result = prime * result + ( ( encPart == null ) ? 0 : encPart.hashCode() );
362         result = prime * result + ( ( realm == null ) ? 0 : realm.hashCode() );
363         result = prime * result + ( ( sName == null ) ? 0 : sName.hashCode() );
364         return result;
365     }
366 
367 
368     /**
369      * {@inheritDoc}
370      */
371     @Override
372     public boolean equals( Object obj )
373     {
374         if ( this == obj )
375         {
376             return true;
377         }
378 
379         if ( !( obj instanceof Ticket ) )
380         {
381             return false;
382         }
383 
384         Ticket../../../../../../org/apache/directory/shared/kerberos/messages/Ticket.html#Ticket">Ticket other = ( Ticket ) obj;
385 
386         if ( encPart == null )
387         {
388             if ( other.encPart != null )
389             {
390                 return false;
391             }
392         }
393         else if ( !encPart.equals( other.encPart ) )
394         {
395             return false;
396         }
397 
398         if ( realm == null )
399         {
400             if ( other.realm != null )
401             {
402                 return false;
403             }
404         }
405         else if ( !realm.equals( other.realm ) )
406         {
407             return false;
408         }
409 
410         if ( sName == null )
411         {
412             if ( other.sName != null )
413             {
414                 return false;
415             }
416         }
417         else if ( !sName.equals( other.sName ) )
418         {
419             return false;
420         }
421 
422         return true;
423     }
424 
425 
426     /**
427      * Pretty print the instance
428      */
429     public String toString( String tabs )
430     {
431         StringBuilder sb = new StringBuilder();
432 
433         sb.append( tabs ).append( "Ticket :\n" );
434         sb.append( tabs ).append( "  tkt-vno : " ).append( getProtocolVersionNumber() ).append( "\n" );
435         sb.append( tabs ).append( "  realm : " ).append( realm ).append( "\n" );
436         sb.append( tabs ).append( "  sname : " ).append( sName ).append( "\n" );
437         sb.append( tabs ).append( "  enc-part : " ).append( encPart ).append( "\n" );
438 
439         return sb.toString();
440     }
441 
442 
443     /**
444      * @see Object#toString()
445      */
446     public String toString()
447     {
448         return toString( "" );
449     }
450 }