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: 902575 $, $Date: 2010-01-24 15:38:06 +0100 (Sun, 24 Jan 2010) $ 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.i18n.I18n; 099 import org.apache.directory.server.kerberos.shared.KerberosUtils; 100 import org.apache.directory.server.kerberos.shared.messages.value.types.PrincipalNameType; 101 import org.apache.directory.shared.asn1.AbstractAsn1Object; 102 import org.apache.directory.shared.asn1.ber.tlv.TLV; 103 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag; 104 import org.apache.directory.shared.asn1.ber.tlv.Value; 105 import org.apache.directory.shared.asn1.codec.EncoderException; 106 import org.apache.directory.shared.ldap.util.StringTools; 107 import org.slf4j.Logger; 108 import org.slf4j.LoggerFactory; 109 110 111 /** 112 * A principal Name, composed of a type and N names. 113 * 114 * PrincipalName ::= SEQUENCE { 115 * name-type [0] Int32, 116 * name-string [1] SEQUENCE OF KerberosString 117 * } 118 * 119 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 120 * @version $Rev: 902575 $, $Date: 2010-01-24 15:38:06 +0100 (Sun, 24 Jan 2010) $ 121 */ 122 public class PrincipalName extends AbstractAsn1Object 123 { 124 /** The logger */ 125 private static final Logger LOG = LoggerFactory.getLogger( PrincipalName.class ); 126 127 /** Speedup for logs */ 128 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 129 130 /** The type for this principal */ 131 private PrincipalNameType nameType; 132 133 /** The principal name - we may have more than one - */ 134 private List<String> nameString; 135 136 /** The principal name as a byte[], for encoding purpose */ 137 private transient List<byte[]> nameBytes; 138 139 // Storage for computed lengths 140 private transient int principalNameSeqLength; 141 private transient int principalTypeTagLength; 142 private transient int principalTypeLength; 143 private transient int principalStringsTagLength; 144 private transient int principalStringsSeqLength; 145 146 /** 147 * Creates a new empty instance of PrincipalName. 148 */ 149 public PrincipalName() 150 { 151 } 152 153 /** 154 * Creates a new instance of PrincipalName, given a KerberosPrincipal. 155 * 156 * We assume that a principal has only one type, even if there are 157 * more than one name component. 158 * 159 * @param principal A Sun kerberosPrincipal instance 160 */ 161 public PrincipalName( KerberosPrincipal principal ) 162 { 163 try 164 { 165 nameString = KerberosUtils.getNames( principal ); 166 } 167 catch ( ParseException pe ) 168 { 169 nameString = KerberosUtils.EMPTY_PRINCIPAL_NAME; 170 } 171 172 this.nameType = PrincipalNameType.getTypeByOrdinal( principal.getNameType() ); 173 } 174 175 /** 176 * Creates a new instance of PrincipalName given a String and an 177 * prinipal type. 178 * 179 * @param nameString The name string, which can contains more than one nameComponent 180 * @param nameType The principal name 181 */ 182 public PrincipalName( String nameString, PrincipalNameType nameType ) throws ParseException 183 { 184 this.nameString = KerberosUtils.getNames( nameString ); 185 186 this.nameType = nameType; 187 } 188 189 190 /** 191 * Creates a new instance of PrincipalName. 192 * 193 * @param nameString 194 * @param nameType 195 */ 196 public PrincipalName( String nameString, int nameType ) throws ParseException 197 { 198 this.nameString = KerberosUtils.getNames( nameString ); 199 200 this.nameType = PrincipalNameType.getTypeByOrdinal( nameType ); 201 } 202 203 204 /** 205 * Returns the type of the {@link PrincipalName}. 206 * 207 * @return The type of the {@link PrincipalName}. 208 */ 209 public PrincipalNameType getNameType() 210 { 211 return nameType; 212 } 213 214 /** 215 * Set the Principal name Type 216 * @param nameType the Principal name Type 217 */ 218 public void setNameType( PrincipalNameType nameType ) 219 { 220 this.nameType = nameType; 221 } 222 223 /** 224 * Set the Principal name Type 225 * @param nameType the Principal name Type 226 */ 227 public void setNameType( int nameType ) 228 { 229 this.nameType = PrincipalNameType.getTypeByOrdinal( nameType ); 230 } 231 232 /** 233 * Returns the name components. 234 * 235 * @return The name components. 236 */ 237 public List<String> getNames() 238 { 239 return nameString; 240 } 241 242 243 /** 244 * @return A String representing the principal names as a String 245 */ 246 public String getNameString() 247 { 248 if ( ( nameString == null ) || ( nameString.size() == 0 ) ) 249 { 250 return ""; 251 } 252 else 253 { 254 StringBuilder sb = new StringBuilder(); 255 boolean isFirst = true; 256 257 for ( String name : nameString ) 258 { 259 if ( isFirst ) 260 { 261 isFirst = false; 262 } 263 else 264 { 265 sb.append( '/' ); 266 } 267 268 sb.append( name ); 269 } 270 271 return sb.toString(); 272 } 273 } 274 275 276 /** 277 * Add a new name to the PrincipalName 278 * @param name The name to add 279 */ 280 public void addName( String name ) 281 { 282 if ( nameString == null ) 283 { 284 nameString = new ArrayList<String>(); 285 } 286 287 nameString.add( name ); 288 } 289 290 291 /** 292 * Compute the PrincipalName length 293 * 294 * PrincipalName : 295 * 296 * 0x30 L1 PrincipalName sequence 297 * | 298 * +--> 0xA1 L2 name-type tag 299 * | | 300 * | +--> 0x02 L2-1 addressType (int) 301 * | 302 * +--> 0xA2 L3 name-string tag 303 * | 304 * +--> 0x30 L3-1 name-string (SEQUENCE OF KerberosString) 305 * | 306 * +--> 0x1B L4[1] value (KerberosString) 307 * | 308 * +--> 0x1B L4[2] value (KerberosString) 309 * | 310 * ... 311 * | 312 * +--> 0x1B L4[n] value (KerberosString) 313 */ 314 public int computeLength() 315 { 316 // The principalName can't be empty. 317 principalTypeLength = Value.getNbBytes( nameType.getOrdinal() ); 318 principalTypeTagLength = 1 + TLV.getNbBytes( principalTypeLength ) + principalTypeLength; 319 320 principalNameSeqLength = 1 + TLV.getNbBytes( principalTypeTagLength ) + principalTypeTagLength; 321 322 // Compute the keyValue 323 if ( ( nameString == null ) || ( nameString.size() == 0 ) ) 324 { 325 principalStringsSeqLength = 0; 326 } 327 else 328 { 329 principalStringsSeqLength = 0; 330 nameBytes = new ArrayList<byte[]>( nameString.size() ); 331 332 for ( String name : nameString ) 333 { 334 if ( name != null ) 335 { 336 byte[] bytes = StringTools.getBytesUtf8( name ); 337 nameBytes.add( bytes ); 338 principalStringsSeqLength += 1 + TLV.getNbBytes( bytes.length ) + bytes.length; 339 } 340 else 341 { 342 nameBytes.add( StringTools.EMPTY_BYTES ); 343 principalStringsSeqLength += 1 + 1; 344 } 345 } 346 } 347 348 principalStringsTagLength = 1 + TLV.getNbBytes( principalStringsSeqLength ) + principalStringsSeqLength; 349 principalNameSeqLength += 1 + TLV.getNbBytes( principalStringsTagLength ) + principalStringsTagLength; 350 351 // Compute the whole sequence length 352 return 1 + TLV.getNbBytes( principalNameSeqLength ) + principalNameSeqLength; 353 } 354 355 356 /** 357 * Encode the PrincipalName message to a PDU. 358 * 359 * PrincipalName : 360 * 361 * 0x30 LL 362 * 0xA0 LL 363 * 0x02 0x01 name-type (integer) 364 * 0xA1 LL 365 * 0x30 LL name-string (SEQUENCE OF KerberosString) 366 * 0x1B LL name-string[1] 367 * 0x1B LL name-string[2] 368 * ... 369 * 0x1B LL name-string[n] 370 * 371 * @param buffer The buffer where to put the PDU. It should have been allocated 372 * before, with the right size. 373 * @return The constructed PDU. 374 */ 375 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 376 { 377 if ( buffer == null ) 378 { 379 throw new EncoderException( I18n.err( I18n.ERR_148 ) ); 380 } 381 382 try 383 { 384 // The PrincipalName SEQ Tag 385 buffer.put( UniversalTag.SEQUENCE_TAG ); 386 buffer.put( TLV.getBytes( principalNameSeqLength ) ); 387 388 // The name-type, first the tag, then the value 389 buffer.put( ( byte ) 0xA0 ); 390 buffer.put( TLV.getBytes( principalTypeTagLength ) ); 391 Value.encode( buffer, nameType.getOrdinal() ); 392 393 // The name-string tag 394 buffer.put( ( byte ) 0xA1 ); 395 buffer.put( TLV.getBytes( principalStringsTagLength ) ); 396 397 // The name-string sequence 398 buffer.put( UniversalTag.SEQUENCE_TAG ); 399 400 if ( ( nameString == null ) || ( nameString.size() == 0 ) ) 401 { 402 buffer.put( ( byte ) 0x00 ); 403 } 404 else 405 { 406 buffer.put( TLV.getBytes( principalStringsSeqLength ) ); 407 408 // The kerberosStrings 409 for ( byte[] name : nameBytes ) 410 { 411 buffer.put( UniversalTag.GENERALIZED_STRING_TAG ); 412 413 if ( ( name == null ) || ( name.length == 0 ) ) 414 { 415 buffer.put( ( byte ) 0x00 ); 416 } 417 else 418 { 419 buffer.put( TLV.getBytes( name.length ) ); 420 buffer.put( name ); 421 } 422 } 423 } 424 } 425 catch ( BufferOverflowException boe ) 426 { 427 LOG.error( I18n.err( I18n.ERR_146, 1 + TLV.getNbBytes( principalNameSeqLength ) 428 + principalNameSeqLength, buffer.capacity() ) ); 429 throw new EncoderException( I18n.err( I18n.ERR_138 ) ); 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 }