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.components; 021 022 023 import java.nio.BufferOverflowException; 024 import java.nio.ByteBuffer; 025 import java.text.ParseException; 026 027 import javax.security.auth.kerberos.KerberosPrincipal; 028 029 import org.apache.directory.server.i18n.I18n; 030 import org.apache.directory.server.kerberos.shared.KerberosConstants; 031 import org.apache.directory.server.kerberos.shared.KerberosUtils; 032 import org.apache.directory.server.kerberos.shared.exceptions.ErrorType; 033 import org.apache.directory.server.kerberos.shared.messages.value.EncryptedData; 034 import org.apache.directory.server.kerberos.shared.messages.value.PrincipalName; 035 import org.apache.directory.shared.asn1.AbstractAsn1Object; 036 import org.apache.directory.shared.asn1.ber.tlv.TLV; 037 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag; 038 import org.apache.directory.shared.asn1.ber.tlv.Value; 039 import org.apache.directory.shared.asn1.codec.EncoderException; 040 import org.apache.directory.shared.ldap.util.StringTools; 041 import org.slf4j.Logger; 042 import org.slf4j.LoggerFactory; 043 044 045 /** 046 * Ticket message component as handed out by the ticket granting service. 047 * 048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 049 * @version $Rev: 910150 $, $Date: 2010-02-15 02:37:34 +0100 (Mon, 15 Feb 2010) $ 050 */ 051 public class Ticket extends AbstractAsn1Object 052 { 053 /** The logger */ 054 private static final Logger LOG = LoggerFactory.getLogger( Ticket.class ); 055 056 /** Speedup for logs */ 057 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 058 059 /** Constant for the {@link Ticket} version number (5) */ 060 public static final int TICKET_VNO = KerberosConstants.KERBEROS_V5; 061 062 /** The Kerberos version number. Should be 5 */ 063 private int tktvno; 064 065 /** A storage for a byte array representation of the realm */ 066 private byte[] realmBytes; 067 068 /** The server principal name */ 069 private PrincipalName sName; 070 071 /** The server realm */ 072 private String realm; 073 074 /** The encoded part */ 075 private EncryptedData encPart; 076 077 /** The decoded ticket part */ 078 private EncTicketPart encTicketPart; 079 080 // Storage for computed lengths 081 private transient int tktvnoLength; 082 private transient int realmLength; 083 private transient int sNameLength; 084 private transient int encPartLength; 085 private transient int ticketSeqLength; 086 private transient int ticketLength; 087 088 /** 089 * Creates a new instance of Ticket. 090 * 091 * @param serverPrincipal The server principal 092 * @param encPart The encoded part 093 */ 094 public Ticket( KerberosPrincipal serverPrincipal, EncryptedData encPart ) throws InvalidTicketException 095 { 096 this( TICKET_VNO, serverPrincipal, encPart ); 097 098 setServerPrincipal( serverPrincipal ); 099 } 100 101 102 /** 103 * Creates a new instance of Ticket. 104 */ 105 public Ticket() 106 { 107 } 108 109 110 /** 111 * Creates a new instance of Ticket. 112 * 113 * @param tktvno The Kerberos version number 114 * @param serverPrincipal The server principal 115 * @param encPart The encoded part 116 */ 117 public Ticket( int tktvno, KerberosPrincipal serverPrincipal, EncryptedData encPart ) throws InvalidTicketException 118 { 119 this.tktvno = tktvno; 120 this.encPart = encPart; 121 setServerPrincipal( serverPrincipal ); 122 } 123 124 125 /** 126 * Sets the {@link EncTicketPart}. 127 * 128 * @param decryptedPart 129 */ 130 public void setEncTicketPart( EncTicketPart decryptedPart ) 131 { 132 encTicketPart = decryptedPart; 133 } 134 135 136 /** 137 * Returns the version number. 138 * 139 * @return The version number. 140 */ 141 public int getTktVno() 142 { 143 return tktvno; 144 } 145 146 147 /** 148 * Set the ticket version number 149 * @param tktvno the ticket version number 150 */ 151 public void setTktVno( int tktvno ) 152 { 153 this.tktvno = tktvno; 154 } 155 156 157 /** 158 * Returns the server {@link PrincipalName}. 159 * 160 * @return The server {@link PrincipalName}. 161 */ 162 public PrincipalName getSName() 163 { 164 return sName; 165 } 166 167 168 /** 169 * Returns the server {@link KerberosPrincipal}. 170 * 171 * @return The server {@link KerberosPrincipal}. 172 */ 173 public KerberosPrincipal getServerPrincipal() 174 { 175 return KerberosUtils.getKerberosPrincipal( sName, realm ); 176 } 177 178 179 /** 180 * Set the server principalName 181 * @param sName the server principalName 182 */ 183 public void setSName( PrincipalName sName ) 184 { 185 this.sName = sName; 186 } 187 188 189 /** 190 * Set the server KerberosPrincipal 191 * @param serverPrincipal the server KerberosPrincipal 192 */ 193 public void setServerPrincipal( KerberosPrincipal serverPrincipal ) throws InvalidTicketException 194 { 195 try 196 { 197 sName = new PrincipalName( serverPrincipal.getName(), serverPrincipal.getNameType() ); 198 realm = serverPrincipal.getRealm(); 199 } 200 catch ( ParseException pe ) 201 { 202 LOG.error( I18n.err( I18n.ERR_135, serverPrincipal, pe.getLocalizedMessage() ) ); 203 throw new InvalidTicketException( ErrorType.KRB_ERR_GENERIC, I18n.err( I18n.ERR_136, pe.getLocalizedMessage() ) ); 204 } 205 } 206 207 208 /** 209 * Returns the server realm. 210 * 211 * @return The server realm. 212 */ 213 public String getRealm() 214 { 215 return realm; 216 } 217 218 219 /** 220 * Set the server realm 221 * @param realm the server realm 222 */ 223 public void setRealm( String realm ) 224 { 225 this.realm = realm; 226 } 227 228 229 /** 230 * Returns the {@link EncryptedData}. 231 * 232 * @return The {@link EncryptedData}. 233 */ 234 public EncryptedData getEncPart() 235 { 236 return encPart; 237 } 238 239 240 /** 241 * Set the encrypted ticket part 242 * @param encPart the encrypted ticket part 243 */ 244 public void setEncPart( EncryptedData encPart ) 245 { 246 this.encPart = encPart; 247 } 248 249 250 /** 251 * Returns the {@link EncTicketPart}. 252 * 253 * @return The {@link EncTicketPart}. 254 */ 255 public EncTicketPart getEncTicketPart() 256 { 257 return encTicketPart; 258 } 259 260 261 /** 262 * Returns the {@link AuthorizationData}. 263 * 264 * @return The {@link AuthorizationData}. 265 * 266 public AuthorizationData getAuthorizationData() 267 { 268 return encTicketPart.getAuthorizationData(); 269 } 270 */ 271 272 /** 273 * Returns the auth {@link KerberosTime}. 274 * 275 * @return The auth {@link KerberosTime}. 276 * 277 public KerberosTime getAuthTime() 278 { 279 return encTicketPart.getAuthTime(); 280 } 281 */ 282 283 /** 284 * Returns the client {@link HostAddresses}. 285 * 286 * @return The client {@link HostAddresses}. 287 * 288 public HostAddresses getClientAddresses() 289 { 290 return encTicketPart.getClientAddresses(); 291 } 292 */ 293 294 /** 295 * Returns the client {@link KerberosPrincipal}. 296 * 297 * @return The client {@link KerberosPrincipal}. 298 * 299 public KerberosPrincipal getClientPrincipal() 300 { 301 return encTicketPart.getClientPrincipal(); 302 } 303 */ 304 305 /** 306 * Returns the client {@link PrincipalName}. 307 * 308 * @return The client {@link PrincipalName}. 309 * 310 public PrincipalName getClientPrincipalName() 311 { 312 return encTicketPart.getClientPrincipalName(); 313 } 314 */ 315 316 /** 317 * Returns the client realm. 318 * 319 * @return The client realm. 320 * 321 public String getClientRealm() 322 { 323 return encTicketPart.getClientRealm(); 324 } 325 */ 326 327 /** 328 * Returns the end {@link KerberosTime}. 329 * 330 * @return The end {@link KerberosTime}. 331 * 332 public KerberosTime getEndTime() 333 { 334 return encTicketPart.getEndTime(); 335 } 336 */ 337 338 /** 339 * Returns the {@link TicketFlags}. 340 * 341 * @return The {@link TicketFlags}. 342 * 343 public TicketFlags getFlags() 344 { 345 return encTicketPart.getFlags(); 346 } 347 */ 348 349 /** 350 * Returns the integer value for the {@link TicketFlags}. 351 * 352 * @return The {@link TicketFlags}. 353 * 354 public int getFlagsIntValue() 355 { 356 return encTicketPart.getFlags().getIntValue(); 357 } 358 */ 359 360 /** 361 * Returns the renew till {@link KerberosTime}. 362 * 363 * @return The renew till {@link KerberosTime}. 364 * 365 public KerberosTime getRenewTill() 366 { 367 return encTicketPart.getRenewTill(); 368 } 369 */ 370 371 /** 372 * Returns the session {@link EncryptionKey}. 373 * 374 * @return The session {@link EncryptionKey}. 375 * 376 public EncryptionKey getSessionKey() 377 { 378 return encTicketPart.getSessionKey(); 379 } 380 */ 381 382 /** 383 * Returns the start {@link KerberosTime}. 384 * 385 * @return The start {@link KerberosTime}. 386 * 387 public KerberosTime getStartTime() 388 { 389 return encTicketPart.getStartTime(); 390 } 391 */ 392 393 /** 394 * Returns the {@link TransitedEncoding}. 395 * 396 * @return The {@link TransitedEncoding}. 397 * 398 public TransitedEncoding getTransitedEncoding() 399 { 400 return encTicketPart.getTransitedEncoding(); 401 } 402 */ 403 404 /** 405 * Returns the flag at the given index. 406 * 407 * @param flag 408 * @return true if the flag at the given index is set. 409 * 410 public boolean getFlag( int flag ) 411 { 412 return encTicketPart.getFlags().isFlagSet( flag ); 413 } 414 */ 415 416 /** 417 * Compute the Ticket length 418 * 419 * Ticket : 420 * 421 * 0x61 L1 Ticket [APPLICATION 1] 422 * | 423 * +--> 0x30 L2 Ticket SEQUENCE 424 * | 425 * +--> 0xA0 L3 tkt-vno tag 426 * | | 427 * | +--> 0x02 L3-1 tkt-vno (int, 5) 428 * | 429 * +--> 0xA1 L4 realm tag 430 * | | 431 * | +--> 0x1B L4-1 realm (KerberosString) 432 * | 433 * +--> 0xA2 L5 sname (PrincipalName) 434 * | 435 * +--> 0xA3 L6 enc-part (EncryptedData) 436 */ 437 public int computeLength() 438 { 439 // Compute the Ticket version length. 440 tktvnoLength = 1 + TLV.getNbBytes( tktvno ) + Value.getNbBytes( tktvno ); 441 442 // Compute the Ticket realm length. 443 realmBytes = StringTools.getBytesUtf8( realm ); 444 realmLength = 1 + TLV.getNbBytes( realmBytes.length ) + realmBytes.length; 445 446 // Compute the principal length 447 sNameLength = sName.computeLength(); 448 449 // Compute the encrypted data 450 encPartLength = encPart.computeLength(); 451 452 // Compute the sequence size 453 ticketSeqLength = 454 1 + TLV.getNbBytes( tktvnoLength ) + tktvnoLength + 455 1 + TLV.getNbBytes( realmLength ) + realmLength + 456 1 + TLV.getNbBytes( sNameLength ) + sNameLength + 457 1 + TLV.getNbBytes( encPartLength ) + encPartLength; 458 459 // compute the global size 460 ticketLength = 1 + TLV.getNbBytes( ticketSeqLength ) + ticketSeqLength; 461 462 return 1 + TLV.getNbBytes( ticketLength ) + ticketLength; 463 } 464 465 /** 466 * Encode the Ticket message to a PDU. 467 * 468 * Ticket : 469 * 470 * 0x61 LL 471 * 0x30 LL 472 * 0xA0 LL tktvno 473 * 0xA1 LL realm 474 * 0xA2 LL 475 * sname (PrincipalName) 476 * 0xA3 LL 477 * enc-part (EncryptedData) 478 * 479 * @return The constructed PDU. 480 */ 481 public ByteBuffer encode() throws EncoderException 482 { 483 ByteBuffer buffer = ByteBuffer.allocate( computeLength() ); 484 485 try 486 { 487 // The Ticket APPLICATION Tag 488 buffer.put( (byte)0x61 ); 489 buffer.put( TLV.getBytes( ticketLength ) ); 490 491 // The Ticket SEQUENCE Tag 492 buffer.put( UniversalTag.SEQUENCE_TAG ); 493 buffer.put( TLV.getBytes( ticketSeqLength ) ); 494 495 // The tkt-vno Tag and value 496 buffer.put( ( byte ) 0xA0 ); 497 buffer.put( TLV.getBytes( tktvnoLength ) ); 498 Value.encode( buffer, tktvno ); 499 500 // The realm Tag and value 501 buffer.put( ( byte ) 0xA1 ); 502 buffer.put( TLV.getBytes( realmLength ) ); 503 buffer.put( UniversalTag.GENERALIZED_STRING_TAG ); 504 buffer.put( TLV.getBytes( realmBytes.length ) ); 505 buffer.put( realmBytes ); 506 507 // The sname Tag and value 508 buffer.put( ( byte ) 0xA2 ); 509 buffer.put( TLV.getBytes( sNameLength ) ); 510 sName.encode( buffer ); 511 512 // The encPartLength Tag and value 513 buffer.put( ( byte ) 0xA3 ); 514 buffer.put( TLV.getBytes( encPartLength ) ); 515 encPart.encode( buffer ); 516 } 517 catch ( BufferOverflowException boe ) 518 { 519 LOG.error( I18n.err( I18n.ERR_137, 1 + TLV.getNbBytes( ticketLength ) + ticketLength, 520 buffer.capacity() ) ); 521 throw new EncoderException( I18n.err( I18n.ERR_138 ) ); 522 } 523 524 if ( IS_DEBUG ) 525 { 526 LOG.debug( "Ticket encoding : {}", StringTools.dumpBytes( buffer.array() ) ); 527 LOG.debug( "Ticket initial value : {}", toString() ); 528 } 529 530 return buffer; 531 } 532 }