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.value;
021
022
023 /**
024 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
025 * @version $Rev: 642496 $, $Date: 2008-03-29 05:09:22 +0200 (Sat, 29 Mar 2008) $
026 *
027 public class PrincipalName
028 {
029 private String nameComponent;
030 private int nameType;
031
032
033 /**
034 * Creates a new instance of PrincipalName.
035 *
036 * @param nameComponent
037 * @param nameType
038 *
039 public PrincipalName( String nameComponent, int nameType )
040 {
041 this.nameComponent = nameComponent;
042 this.nameType = nameType;
043 }
044
045
046 /**
047 * Returns the type of the {@link PrincipalName}.
048 *
049 * @return The type of the {@link PrincipalName}.
050 *
051 public int getNameType()
052 {
053 return nameType;
054 }
055
056
057 /**
058 * Returns the name component.
059 *
060 * @return The name component.
061 *
062 public String getNameComponent()
063 {
064 return nameComponent;
065 }
066 }*/
067
068 /*
069 * Licensed to the Apache Software Foundation (ASF) under one
070 * or more contributor license agreements. See the NOTICE file
071 * distributed with this work for additional information
072 * regarding copyright ownership. The ASF licenses this file
073 * to you under the Apache License, Version 2.0 (the
074 * "License"); you may not use this file except in compliance
075 * with the License. You may obtain a copy of the License at
076 *
077 * http://www.apache.org/licenses/LICENSE-2.0
078 *
079 * Unless required by applicable law or agreed to in writing,
080 * software distributed under the License is distributed on an
081 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
082 * KIND, either express or implied. See the License for the
083 * specific language governing permissions and limitations
084 * under the License.
085 *
086 */
087 package org.apache.directory.server.kerberos.shared.messages.value;
088
089
090 import java.nio.BufferOverflowException;
091 import java.nio.ByteBuffer;
092 import java.text.ParseException;
093 import java.util.ArrayList;
094 import java.util.List;
095
096 import javax.security.auth.kerberos.KerberosPrincipal;
097
098 import org.apache.directory.server.kerberos.shared.KerberosUtils;
099 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 05:09:22 +0200 (Sat, 29 Mar 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 }