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.value;
21  
22  
23  /**
24   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
25   * @version $Rev: 642496 $, $Date: 2008-03-29 04:09:22 +0100 (Sa, 29 Mär 2008) $
26   *
27  public class PrincipalName
28  {
29      private String nameComponent;
30      private int nameType;
31  
32  
33      /**
34       * Creates a new instance of PrincipalName.
35       *
36       * @param nameComponent
37       * @param nameType
38       *
39      public PrincipalName( String nameComponent, int nameType )
40      {
41          this.nameComponent = nameComponent;
42          this.nameType = nameType;
43      }
44  
45  
46      /**
47       * Returns the type of the {@link PrincipalName}.
48       *
49       * @return The type of the {@link PrincipalName}.
50       *
51      public int getNameType()
52      {
53          return nameType;
54      }
55  
56  
57      /**
58       * Returns the name component.
59       *
60       * @return The name component.
61       *
62      public String getNameComponent()
63      {
64          return nameComponent;
65      }
66  }*/
67  
68  /*
69   *  Licensed to the Apache Software Foundation (ASF) under one
70   *  or more contributor license agreements.  See the NOTICE file
71   *  distributed with this work for additional information
72   *  regarding copyright ownership.  The ASF licenses this file
73   *  to you under the Apache License, Version 2.0 (the
74   *  "License"); you may not use this file except in compliance
75   *  with the License.  You may obtain a copy of the License at
76   *  
77   *    http://www.apache.org/licenses/LICENSE-2.0
78   *  
79   *  Unless required by applicable law or agreed to in writing,
80   *  software distributed under the License is distributed on an
81   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
82   *  KIND, either express or implied.  See the License for the
83   *  specific language governing permissions and limitations
84   *  under the License. 
85   *  
86   */
87  package org.apache.directory.server.kerberos.shared.messages.value;
88  
89  
90  import java.nio.BufferOverflowException;
91  import java.nio.ByteBuffer;
92  import java.text.ParseException;
93  import java.util.ArrayList;
94  import java.util.List;
95  
96  import javax.security.auth.kerberos.KerberosPrincipal;
97  
98  import org.apache.directory.server.kerberos.shared.KerberosUtils;
99  import org.apache.directory.server.kerberos.shared.messages.value.types.PrincipalNameType;
100 import org.apache.directory.shared.asn1.AbstractAsn1Object;
101 import org.apache.directory.shared.asn1.ber.tlv.TLV;
102 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
103 import org.apache.directory.shared.asn1.ber.tlv.Value;
104 import org.apache.directory.shared.asn1.codec.EncoderException;
105 import org.apache.directory.shared.ldap.util.StringTools;
106 import org.slf4j.Logger;
107 import org.slf4j.LoggerFactory;
108 
109 
110 /**
111  * A principal Name, composed of a type and N names.
112  * 
113  * PrincipalName   ::= SEQUENCE {
114  *        name-type       [0] Int32,
115  *        name-string     [1] SEQUENCE OF KerberosString
116  * }
117  *
118  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
119  * @version $Rev: 642496 $, $Date: 2008-03-29 04:09:22 +0100 (Sa, 29 Mär 2008) $
120  */
121 public class PrincipalName extends AbstractAsn1Object
122 {
123     /** The logger */
124     private static final Logger LOG = LoggerFactory.getLogger( PrincipalName.class );
125 
126     /** Speedup for logs */
127     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
128 
129     /** The type for this principal */
130     private PrincipalNameType nameType;
131 
132     /** The principal name - we may have more than one - */
133     private List<String> nameString;
134     
135     /** The principal name as a byte[], for encoding purpose */
136     private transient List<byte[]> nameBytes;
137     
138     // Storage for computed lengths
139     private transient int principalNameSeqLength;
140     private transient int principalTypeTagLength;
141     private transient int principalTypeLength;
142     private transient int principalStringsTagLength;
143     private transient int principalStringsSeqLength;
144 
145     /**
146      * Creates a new empty instance of PrincipalName.
147      */
148     public PrincipalName()
149     {
150     }
151 
152     /**
153      * Creates a new instance of PrincipalName, given a KerberosPrincipal.
154      * 
155      * We assume that a principal has only one type, even if there are
156      * more than one name component.
157      *
158      * @param principal A Sun kerberosPrincipal instance
159      */
160     public PrincipalName( KerberosPrincipal principal )
161     {
162         try
163         {
164             nameString = KerberosUtils.getNames( principal );
165         }
166         catch ( ParseException pe )
167         {
168             nameString = KerberosUtils.EMPTY_PRINCIPAL_NAME;
169         }
170 
171         this.nameType = PrincipalNameType.getTypeByOrdinal( principal.getNameType() );
172     }
173     
174     /**
175      * Creates a new instance of PrincipalName given a String and an 
176      * prinipal type.
177      * 
178      * @param nameString The name string, which can contains more than one nameComponent
179      * @param nameType The principal name
180      */
181     public PrincipalName( String nameString, PrincipalNameType nameType )  throws ParseException
182     {
183         this.nameString = KerberosUtils.getNames( nameString );
184         
185         this.nameType = nameType;
186     }
187 
188 
189     /**
190      * Creates a new instance of PrincipalName.
191      *
192      * @param nameString
193      * @param nameType
194      */
195     public PrincipalName( String nameString, int nameType ) throws ParseException
196     {
197         this.nameString = KerberosUtils.getNames( nameString );
198         
199         this.nameType = PrincipalNameType.getTypeByOrdinal( nameType );
200     }
201 
202 
203     /**
204      * Returns the type of the {@link PrincipalName}.
205      *
206      * @return The type of the {@link PrincipalName}.
207      */
208     public PrincipalNameType getNameType()
209     {
210         return nameType;
211     }
212                     
213     /** 
214      * Set the Principal name Type
215      * @param nameType the Principal name Type
216      */
217     public void setNameType( PrincipalNameType nameType )
218     {
219         this.nameType = nameType;
220     }
221 
222     /** 
223      * Set the Principal name Type
224      * @param nameType the Principal name Type
225      */
226     public void setNameType( int nameType )
227     {
228         this.nameType = PrincipalNameType.getTypeByOrdinal( nameType );
229     }
230 
231     /**
232      * Returns the name components.
233      *
234      * @return The name components.
235      */
236     public List<String> getNames()
237     {
238         return nameString;
239     }
240 
241 
242     /**
243      * @return A String representing the principal names as a String 
244      */
245     public String getNameString()
246     {
247         if ( ( nameString == null ) || ( nameString.size() == 0 ) )
248         {
249             return "";
250         }
251         else
252         {
253             StringBuilder sb = new StringBuilder();
254             boolean isFirst = true;
255 
256             for ( String name : nameString )
257             {
258                 if ( isFirst )
259                 {
260                     isFirst = false;
261                 }
262                 else
263                 {
264                     sb.append( '/' );
265                 }
266 
267                 sb.append( name );
268             }
269 
270             return sb.toString();
271         }
272     }
273 
274 
275     /**
276      * Add a new name to the PrincipalName
277      * @param name The name to add
278      */
279     public void addName( String name )
280     {
281         if ( nameString == null )
282         {
283             nameString = new ArrayList<String>();
284         }
285 
286         nameString.add( name );
287     }
288 
289 
290     /**
291      * Compute the PrincipalName length
292      * 
293      * PrincipalName :
294      * 
295      * 0x30 L1 PrincipalName sequence
296      *  |
297      *  +--> 0xA1 L2 name-type tag
298      *  |     |
299      *  |     +--> 0x02 L2-1 addressType (int)
300      *  |
301      *  +--> 0xA2 L3 name-string tag
302      *        |
303      *        +--> 0x30 L3-1 name-string (SEQUENCE OF KerberosString)
304      *              |
305      *              +--> 0x1B L4[1] value (KerberosString)
306      *              |
307      *              +--> 0x1B L4[2] value (KerberosString)
308      *              |
309      *              ...
310      *              |
311      *              +--> 0x1B L4[n] value (KerberosString)
312      */
313     public int computeLength()
314     {
315         // The principalName can't be empty.
316         principalTypeLength = Value.getNbBytes( nameType.getOrdinal() );
317         principalTypeTagLength = 1 + TLV.getNbBytes( principalTypeLength ) + principalTypeLength;
318         
319         principalNameSeqLength = 1 + TLV.getNbBytes( principalTypeTagLength ) + principalTypeTagLength;
320 
321         // Compute the keyValue
322         if ( ( nameString == null ) || ( nameString.size() == 0 ) )
323         {
324             principalStringsSeqLength = 0;
325         }
326         else
327         {
328             principalStringsSeqLength = 0;
329             nameBytes = new ArrayList<byte[]>( nameString.size() );
330 
331             for ( String name : nameString )
332             {
333                 if ( name != null )
334                 {
335                     byte[] bytes = StringTools.getBytesUtf8( name );
336                     nameBytes.add( bytes );
337                     principalStringsSeqLength += 1 + TLV.getNbBytes( bytes.length ) + bytes.length;
338                 }
339                 else
340                 {
341                     nameBytes.add( StringTools.EMPTY_BYTES );
342                     principalStringsSeqLength += 1 + 1;
343                 }
344             }
345         }
346 
347         principalStringsTagLength = 1 + TLV.getNbBytes( principalStringsSeqLength ) + principalStringsSeqLength;
348         principalNameSeqLength += 1 + TLV.getNbBytes( principalStringsTagLength ) + principalStringsTagLength;
349 
350         // Compute the whole sequence length
351         return 1 + TLV.getNbBytes( principalNameSeqLength ) + principalNameSeqLength;
352     }
353 
354 
355     /**
356      * Encode the PrincipalName message to a PDU. 
357      * 
358      * PrincipalName :
359      * 
360      * 0x30 LL
361      *   0xA0 LL 
362      *     0x02 0x01 name-type (integer)
363      *   0xA1 LL 
364      *     0x30 LL name-string (SEQUENCE OF KerberosString)
365      *       0x1B LL name-string[1]
366      *       0x1B LL name-string[2]
367      *       ...
368      *       0x1B LL name-string[n]
369      * 
370      * @param buffer The buffer where to put the PDU. It should have been allocated
371      * before, with the right size.
372      * @return The constructed PDU.
373      */
374     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
375     {
376         if ( buffer == null )
377         {
378             throw new EncoderException( "Cannot put a PDU in a null buffer !" );
379         }
380 
381         try
382         {
383             // The PrincipalName SEQ Tag
384             buffer.put( UniversalTag.SEQUENCE_TAG );
385             buffer.put( TLV.getBytes( principalNameSeqLength ) );
386 
387             // The name-type, first the tag, then the value
388             buffer.put( ( byte ) 0xA0 );
389             buffer.put( TLV.getBytes( principalTypeTagLength ) );
390             Value.encode( buffer, nameType.getOrdinal() );
391 
392             // The name-string tag
393             buffer.put( ( byte ) 0xA1 );
394             buffer.put( TLV.getBytes( principalStringsTagLength ) );
395 
396             // The name-string sequence
397             buffer.put( UniversalTag.SEQUENCE_TAG );
398 
399             if ( ( nameString == null ) || ( nameString.size() == 0 ) )
400             {
401                 buffer.put( ( byte ) 0x00 );
402             }
403             else
404             {
405                 buffer.put( TLV.getBytes( principalStringsSeqLength ) );
406 
407                 // The kerberosStrings
408                 for ( byte[] name : nameBytes )
409                 {
410                     buffer.put( UniversalTag.GENERALIZED_STRING_TAG );
411 
412                     if ( ( name == null ) || ( name.length == 0 ) )
413                     {
414                         buffer.put( ( byte ) 0x00 );
415                     }
416                     else
417                     {
418                         buffer.put( TLV.getBytes( name.length ) );
419                         buffer.put( name );
420                     }
421                 }
422             }
423         }
424         catch ( BufferOverflowException boe )
425         {
426             LOG.error(
427                 "Cannot encode the principalName object, the PDU size is {} when only {} bytes has been allocated", 1
428                     + TLV.getNbBytes( principalNameSeqLength ) + principalNameSeqLength, buffer.capacity() );
429             throw new EncoderException( "The PDU buffer size is too small !" );
430         }
431 
432         if ( IS_DEBUG )
433         {
434             LOG.debug( "PrinipalName encoding : {}", StringTools.dumpBytes( buffer.array() ) );
435             LOG.debug( "PrinipalName initial value : {}", toString() );
436         }
437 
438         return buffer;
439     }
440 
441 
442     /**
443      * @see Object#toString()
444      */
445     public String toString()
446     {
447         StringBuilder sb = new StringBuilder();
448 
449         sb.append( "PincipalName : {\n" );
450 
451         sb.append( "    name-type: " ).append( nameType ).append( '\n' );
452 
453         if ( ( nameString != null ) && ( nameString.size() != 0 ) )
454         {
455             sb.append( "    name-string : <" );
456             boolean isFirst = true;
457 
458             for ( String name : nameString )
459             {
460                 if ( isFirst )
461                 {
462                     isFirst = false;
463                 }
464                 else
465                 {
466                     sb.append( ", " );
467                 }
468 
469                 sb.append( '\'' ).append( name ).append( '\'' );
470             }
471 
472             sb.append( ">\n}" );
473         }
474         else
475         {
476             sb.append( "    no name-string\n}" );
477         }
478 
479         return sb.toString();
480     }
481 }