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