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 */ 020package org.apache.directory.shared.kerberos.components; 021 022 023import java.nio.ByteBuffer; 024import java.util.ArrayList; 025import java.util.LinkedHashSet; 026import java.util.List; 027import java.util.Set; 028 029import org.apache.directory.api.asn1.Asn1Object; 030import org.apache.directory.api.asn1.EncoderException; 031import org.apache.directory.api.asn1.ber.tlv.BerValue; 032import org.apache.directory.api.asn1.ber.tlv.TLV; 033import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 034import org.apache.directory.api.util.Strings; 035import org.apache.directory.server.i18n.I18n; 036import org.apache.directory.shared.kerberos.KerberosConstants; 037import org.apache.directory.shared.kerberos.KerberosTime; 038import org.apache.directory.shared.kerberos.codec.options.KdcOptions; 039import org.apache.directory.shared.kerberos.codec.types.EncryptionType; 040import org.apache.directory.shared.kerberos.messages.Ticket; 041 042 043/** 044 * The KDC-REQ-BODY data structure. It will store the object described by the ASN.1 grammar : 045 * <pre> 046 * KDC-REQ-BODY ::= SEQUENCE { 047 * kdc-options [0] KDCOptions, 048 * cname [1] PrincipalName OPTIONAL 049 * -- Used only in AS-REQ --, 050 * realm [2] Realm 051 * -- Server's realm 052 * -- Also client's in AS-REQ --, 053 * sname [3] PrincipalName OPTIONAL, 054 * from [4] KerberosTime OPTIONAL, 055 * till [5] KerberosTime, 056 * rtime [6] KerberosTime OPTIONAL, 057 * nonce [7] UInt32, 058 * etype [8] SEQUENCE OF Int32 -- EncryptionType 059 * -- in preference order --, 060 * addresses [9] HostAddresses OPTIONAL, 061 * enc-authorization-data [10] EncryptedData OPTIONAL 062 * -- AuthorizationData --, 063 * additional-tickets [11] SEQUENCE OF Ticket OPTIONAL 064 * -- NOTE: not empty 065 * } 066 * </pre> 067 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 068 */ 069public class KdcReqBody implements Asn1Object 070{ 071 /** The KDC options */ 072 private KdcOptions kdcOptions; 073 074 /** The Client Principal, if the request is an AS-REQ */ 075 private PrincipalName cName; 076 077 /** The realm */ 078 private String realm; 079 080 /** The Server Principal */ 081 private PrincipalName sName; 082 083 /** The start time for the requested ticket */ 084 private KerberosTime from; 085 086 /** The expiration date for the requested ticket */ 087 private KerberosTime till; 088 089 /** The renew-till date for the requested ticket */ 090 private KerberosTime rtime; 091 092 /** Random number to avoid MiM attacks */ 093 private int nonce; 094 095 /** Set of desired encryption types */ 096 private Set<EncryptionType> eType; 097 098 /** Addresses valid for the requested ticket */ 099 private HostAddresses addresses; 100 101 /** Encoded authorizationData, used by the TGS-REQ only */ 102 private EncryptedData encAuthorizationData; 103 104 /** Additional tickets */ 105 private List<Ticket> additionalTickets; 106 107 // Storage for computed lengths 108 private int kdcOptionsLength; 109 private int cNameLength; 110 private int realmLength; 111 private byte[] realmBytes; 112 private int sNameLength; 113 private int fromLength; 114 private int tillLength; 115 private int rtimeLength; 116 private int nonceLength; 117 private int eTypeLength; 118 private int eTypeSeqLength; 119 private int[] eTypeLengths; 120 private int addressesLength; 121 private int encAuthzDataLength; 122 private int additionalTicketLength; 123 private int additionalTicketSeqLength; 124 private int[] additionalTicketsLengths; 125 private int kdcReqBodySeqLength; 126 private int kdcReqBodyLength; 127 128 129 /** 130 * Creates a new instance of RequestBody. 131 */ 132 public KdcReqBody() 133 { 134 additionalTickets = new ArrayList<>(); 135 eType = new LinkedHashSet<>(); 136 } 137 138 139 /** 140 * Returns the additional {@link Ticket}s. 141 * 142 * @return The additional {@link Ticket}s. 143 */ 144 public Ticket[] getAdditionalTickets() 145 { 146 return additionalTickets.toArray( new Ticket[] 147 {} ); 148 } 149 150 151 /** 152 * Set the list of additional Ticket 153 * @param additionalTickets the additionalTickets to set 154 */ 155 public void setAdditionalTickets( List<Ticket> additionalTickets ) 156 { 157 this.additionalTickets = additionalTickets; 158 } 159 160 161 /** 162 * Add a new Ticket to the list of additional tickets 163 * @param additionalTicket the additionalTicket to set 164 */ 165 public void addAdditionalTicket( Ticket additionalTicket ) 166 { 167 this.additionalTickets.add( additionalTicket ); 168 } 169 170 171 /** 172 * Returns the {@link HostAddresses}. 173 * 174 * @return The {@link HostAddresses}. 175 */ 176 public HostAddresses getAddresses() 177 { 178 return addresses; 179 } 180 181 182 /** 183 * @param addresses the addresses to set 184 */ 185 public void setAddresses( HostAddresses addresses ) 186 { 187 this.addresses = addresses; 188 } 189 190 191 /** 192 * @return the client PrincipalName 193 */ 194 public PrincipalName getCName() 195 { 196 return cName; 197 } 198 199 200 /** 201 * @param cName the cName to set 202 */ 203 public void setCName( PrincipalName cName ) 204 { 205 this.cName = cName; 206 } 207 208 209 /** 210 * Returns the encrypted {@link AuthorizationData} as {@link EncryptedData}. 211 * 212 * @return The encrypted {@link AuthorizationData} as {@link EncryptedData}. 213 */ 214 public EncryptedData getEncAuthorizationData() 215 { 216 return encAuthorizationData; 217 } 218 219 220 /** 221 * @param encAuthorizationData the encAuthorizationData to set 222 */ 223 public void setEncAuthorizationData( EncryptedData encAuthorizationData ) 224 { 225 this.encAuthorizationData = encAuthorizationData; 226 } 227 228 229 /** 230 * Returns the requested {@link EncryptionType}s. 231 * 232 * @return The requested {@link EncryptionType}s. 233 */ 234 public Set<EncryptionType> getEType() 235 { 236 return eType; 237 } 238 239 240 /** 241 * @param eType the eType to set 242 */ 243 public void setEType( Set<EncryptionType> eType ) 244 { 245 this.eType = eType; 246 } 247 248 249 /** 250 * @param eType the eType to add 251 */ 252 public void addEType( EncryptionType eType ) 253 { 254 this.eType.add( eType ); 255 } 256 257 258 /** 259 * Returns the from {@link KerberosTime}. 260 * 261 * @return The from {@link KerberosTime}. 262 */ 263 public KerberosTime getFrom() 264 { 265 return from; 266 } 267 268 269 /** 270 * @param from the from to set 271 */ 272 public void setFrom( KerberosTime from ) 273 { 274 this.from = from; 275 } 276 277 278 /** 279 * Returns the {@link KdcOptions}. 280 * 281 * @return The {@link KdcOptions}. 282 */ 283 public KdcOptions getKdcOptions() 284 { 285 return kdcOptions; 286 } 287 288 289 /** 290 * @param kdcOptions the kdcOptions to set 291 */ 292 public void setKdcOptions( KdcOptions kdcOptions ) 293 { 294 this.kdcOptions = kdcOptions; 295 } 296 297 298 /** 299 * Returns the nonce. 300 * 301 * @return The nonce. 302 */ 303 public int getNonce() 304 { 305 return nonce; 306 } 307 308 309 /** 310 * @param nonce the nonce to set 311 */ 312 public void setNonce( int nonce ) 313 { 314 this.nonce = nonce; 315 } 316 317 318 /** 319 * @return the realm 320 */ 321 public String getRealm() 322 { 323 return realm; 324 } 325 326 327 /** 328 * @param realm the realm to set 329 */ 330 public void setRealm( String realm ) 331 { 332 this.realm = realm; 333 } 334 335 336 /** 337 * Returns the RenewTime {@link KerberosTime}. 338 * 339 * @return The RenewTime {@link KerberosTime}. 340 */ 341 public KerberosTime getRTime() 342 { 343 return rtime; 344 } 345 346 347 /** 348 * @param rtime the renewTime to set 349 */ 350 public void setRtime( KerberosTime rtime ) 351 { 352 this.rtime = rtime; 353 } 354 355 356 /** 357 * Returns the server {@link PrincipalName}. 358 * 359 * @return The server {@link PrincipalName}. 360 */ 361 public PrincipalName getSName() 362 { 363 return sName; 364 } 365 366 367 /** 368 * @param sName the sName to set 369 */ 370 public void setSName( PrincipalName sName ) 371 { 372 this.sName = sName; 373 } 374 375 376 /** 377 * Returns the till {@link KerberosTime}. 378 * 379 * @return The till {@link KerberosTime}. 380 */ 381 public KerberosTime getTill() 382 { 383 return till; 384 } 385 386 387 /** 388 * @param till the till to set 389 */ 390 public void setTill( KerberosTime till ) 391 { 392 this.till = till; 393 } 394 395 396 /** 397 * Compute the KdcReqBody length 398 * <pre> 399 * KdcReqBody : 400 * 401 * 0x30 L1 KdcReqBody sequence 402 * | 403 * +--> 0xA0 L2 kdc-options tag 404 * | | 405 * | +--> 0x03 L2-1 kdc-options (BitString) 406 * | 407 * +--> 0xA1 L3 cname tag 408 * | | 409 * | +--> 0x30 L3-1 cname (PrincipalName) 410 * | 411 * +--> 0xA2 L4 realm tag 412 * | | 413 * | +--> 0x1B L4-1 realm (Realm, KerberosString) 414 * | 415 * +--> 0xA3 L5 sname tag 416 * | | 417 * | +--> 0x30 L5-1 sname (PrincipalName) 418 * | 419 * +--> 0xA4 L6 from tag 420 * | | 421 * | +--> 0x18 L6-1 from (KerberosTime) 422 * | 423 * +--> 0xA5 L7 till tag 424 * | | 425 * | +--> 0x18 L7-1 till (KerberosTime) 426 * | 427 * +--> 0xA6 L8 rtime tag 428 * | | 429 * | +--> 0x18 L8-1 rtime (KerberosTime) 430 * | 431 * +--> 0xA7 L9 nonce tag 432 * | | 433 * | +--> 0x02 L9-1 nonce (Int) 434 * | 435 * +--> 0xA8 L10 etype tag 436 * | | 437 * | +--> 0x30 L10-1 SEQ 438 * | | 439 * | +--> 0x02 L10-1-1 etype 440 * | | 441 * | +--> 0x02 L10-1-2 etype 442 * | | 443 * | : 444 * | 445 * +--> 0xA9 L11 addresses tag 446 * | | 447 * | +--> 0x30 L11-1 addresses (HostAddresses) 448 * | 449 * +--> 0xAA L12 enc-authorization-data tag 450 * | | 451 * | +--> 0x30 L12-1 enc-authorization-data 452 * | 453 * +--> 0xAB L13 additional-tickets tag 454 * | 455 * +--> 0x30 L13-1 additional-tickets 456 * | 457 * +--> 0x61 L13-1-1 Ticket 458 * | 459 * +--> 0x61 L13-1-2 Ticket 460 * | 461 * : 462 * </pre> 463 */ 464 @Override 465 public int computeLength() 466 { 467 reset(); 468 469 // The KdcOptions length 470 kdcOptionsLength = 1 + 1 + kdcOptions.getBytes().length; 471 kdcReqBodySeqLength = 1 + TLV.getNbBytes( kdcOptionsLength ) + kdcOptionsLength; 472 473 // The cname length 474 if ( cName != null ) 475 { 476 cNameLength = cName.computeLength(); 477 kdcReqBodySeqLength += 1 + TLV.getNbBytes( cNameLength ) + cNameLength; 478 } 479 480 // Compute the realm length. 481 realmBytes = Strings.getBytesUtf8( realm ); 482 realmLength = 1 + TLV.getNbBytes( realmBytes.length ) + realmBytes.length; 483 kdcReqBodySeqLength += 1 + TLV.getNbBytes( realmLength ) + realmLength; 484 485 // The sname length 486 if ( sName != null ) 487 { 488 sNameLength = sName.computeLength(); 489 kdcReqBodySeqLength += 1 + TLV.getNbBytes( sNameLength ) + sNameLength; 490 } 491 492 // The from length 493 if ( from != null ) 494 { 495 fromLength = 1 + 1 + 0x0F; 496 kdcReqBodySeqLength += 1 + 1 + fromLength; 497 } 498 499 // The till length 500 tillLength = 1 + 1 + 0x0F; 501 kdcReqBodySeqLength += 1 + 1 + tillLength; 502 503 // The rtime length 504 if ( rtime != null ) 505 { 506 rtimeLength = 1 + 1 + 0x0F; 507 kdcReqBodySeqLength += 1 + 1 + rtimeLength; 508 } 509 510 // The nonce length 511 nonceLength = 1 + 1 + BerValue.getNbBytes( nonce ); 512 kdcReqBodySeqLength += 1 + 1 + nonceLength; 513 514 // The eType length 515 eTypeLengths = new int[eType.size()]; 516 int pos = 0; 517 eTypeSeqLength = 0; 518 519 for ( EncryptionType encryptionType : eType ) 520 { 521 eTypeLengths[pos] = 1 + 1 + BerValue.getNbBytes( encryptionType.getValue() ); 522 eTypeSeqLength += eTypeLengths[pos]; 523 pos++; 524 } 525 526 eTypeLength = 1 + TLV.getNbBytes( eTypeSeqLength ) + eTypeSeqLength; 527 kdcReqBodySeqLength += 1 + TLV.getNbBytes( eTypeLength ) + eTypeLength; 528 529 // The Addresses length 530 if ( addresses != null ) 531 { 532 addressesLength = addresses.computeLength(); 533 kdcReqBodySeqLength += 1 + TLV.getNbBytes( addressesLength ) + addressesLength; 534 } 535 536 // The EncAuthorizationData length 537 if ( encAuthorizationData != null ) 538 { 539 encAuthzDataLength = encAuthorizationData.computeLength(); 540 kdcReqBodySeqLength += 1 + TLV.getNbBytes( encAuthzDataLength ) + encAuthzDataLength; 541 } 542 543 // The additionalTickets length 544 if ( !additionalTickets.isEmpty() ) 545 { 546 additionalTicketsLengths = new int[additionalTickets.size()]; 547 additionalTicketSeqLength = 0; 548 pos = 0; 549 550 for ( Ticket ticket : additionalTickets ) 551 { 552 additionalTicketsLengths[pos] = ticket.computeLength(); 553 additionalTicketSeqLength += additionalTicketsLengths[pos]; 554 pos++; 555 } 556 557 additionalTicketLength = 1 + TLV.getNbBytes( additionalTicketSeqLength ) + additionalTicketSeqLength; 558 kdcReqBodySeqLength += 1 + TLV.getNbBytes( additionalTicketLength ) + additionalTicketLength; 559 } 560 561 // compute the global size 562 kdcReqBodyLength = 1 + TLV.getNbBytes( kdcReqBodySeqLength ) + kdcReqBodySeqLength; 563 564 return kdcReqBodyLength; 565 } 566 567 568 /** 569 * Encode the KDC-REQ-BODY component 570 * 571 * @param buffer The buffer containing the encoded result 572 * @return The encoded component 573 * @throws EncoderException If the encoding failed 574 */ 575 @Override 576 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 577 { 578 if ( buffer == null ) 579 { 580 throw new EncoderException( I18n.err( I18n.ERR_148 ) ); 581 } 582 583 // The KDC-REQ-BODY SEQ Tag 584 buffer.put( UniversalTag.SEQUENCE.getValue() ); 585 buffer.put( TLV.getBytes( kdcReqBodySeqLength ) ); 586 587 // The KdcOptions ----------------------------------------------------- 588 // The tag 589 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_KDC_OPTIONS_TAG ); 590 buffer.put( TLV.getBytes( kdcOptionsLength ) ); 591 592 // The value 593 BerValue.encode( buffer, kdcOptions ); 594 595 // The cname if any --------------------------------------------------- 596 if ( cName != null ) 597 { 598 // The tag 599 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_CNAME_TAG ); 600 buffer.put( TLV.getBytes( cNameLength ) ); 601 602 // The value 603 cName.encode( buffer ); 604 } 605 606 // The realm ---------------------------------------------------------- 607 // The tag 608 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_REALM_TAG ); 609 buffer.put( TLV.getBytes( realmLength ) ); 610 611 // The value 612 buffer.put( UniversalTag.GENERAL_STRING.getValue() ); 613 buffer.put( TLV.getBytes( realmBytes.length ) ); 614 buffer.put( realmBytes ); 615 616 // The sname, if any -------------------------------------------------- 617 if ( sName != null ) 618 { 619 // The tag 620 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_SNAME_TAG ); 621 buffer.put( TLV.getBytes( sNameLength ) ); 622 623 // The value 624 sName.encode( buffer ); 625 } 626 627 // The from, if any --------------------------------------------------- 628 if ( from != null ) 629 { 630 // The tag 631 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_FROM_TAG ); 632 buffer.put( TLV.getBytes( fromLength ) ); 633 634 // The value 635 buffer.put( UniversalTag.GENERALIZED_TIME.getValue() ); 636 buffer.put( ( byte ) 0x0F ); 637 buffer.put( from.getBytes() ); 638 } 639 640 // The till ----------------------------------------------------------- 641 // The tag 642 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_TILL_TAG ); 643 buffer.put( TLV.getBytes( tillLength ) ); 644 645 // The value 646 buffer.put( UniversalTag.GENERALIZED_TIME.getValue() ); 647 buffer.put( ( byte ) 0x0F ); 648 buffer.put( till.getBytes() ); 649 650 // The rtime if any --------------------------------------------------- 651 if ( rtime != null ) 652 { 653 // The tag 654 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_RTIME_TAG ); 655 buffer.put( TLV.getBytes( rtimeLength ) ); 656 657 // The value 658 buffer.put( UniversalTag.GENERALIZED_TIME.getValue() ); 659 buffer.put( ( byte ) 0x0F ); 660 buffer.put( rtime.getBytes() ); 661 } 662 663 // The nonce ---------------------------------------------------------- 664 // The tag 665 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_NONCE_TAG ); 666 buffer.put( TLV.getBytes( nonceLength ) ); 667 668 // The value 669 BerValue.encode( buffer, nonce ); 670 671 // The etype ---------------------------------------------------------- 672 // The tag 673 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_ETYPE_TAG ); 674 buffer.put( TLV.getBytes( eTypeLength ) ); 675 676 // The sequence 677 buffer.put( UniversalTag.SEQUENCE.getValue() ); 678 buffer.put( TLV.getBytes( eTypeSeqLength ) ); 679 680 // The values 681 for ( EncryptionType encryptionType : eType ) 682 { 683 BerValue.encode( buffer, encryptionType.getValue() ); 684 } 685 686 // The addresses if any ----------------------------------------------- 687 if ( addresses != null ) 688 { 689 // The tag 690 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_ADDRESSES_TAG ); 691 buffer.put( TLV.getBytes( addressesLength ) ); 692 693 // The value 694 addresses.encode( buffer ); 695 } 696 697 // The enc-authorization-data, if any --------------------------------- 698 if ( encAuthorizationData != null ) 699 { 700 // The tag 701 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_ENC_AUTHZ_DATA_TAG ); 702 buffer.put( TLV.getBytes( encAuthzDataLength ) ); 703 704 // The value 705 encAuthorizationData.encode( buffer ); 706 } 707 708 // The additional-tickets, if any ------------------------------------- 709 if ( !additionalTickets.isEmpty() ) 710 { 711 // The tag 712 buffer.put( ( byte ) KerberosConstants.KDC_REQ_BODY_ADDITIONAL_TICKETS_TAG ); 713 buffer.put( TLV.getBytes( additionalTicketLength ) ); 714 715 // The sequence 716 buffer.put( UniversalTag.SEQUENCE.getValue() ); 717 buffer.put( TLV.getBytes( additionalTicketSeqLength ) ); 718 719 // The values 720 for ( Ticket ticket : additionalTickets ) 721 { 722 ticket.encode( buffer ); 723 } 724 } 725 726 return buffer; 727 } 728 729 730 /** 731 * reset the fields used while computing length 732 */ 733 private void reset() 734 { 735 kdcOptionsLength = 0; 736 cNameLength = 0; 737 realmLength = 0; 738 realmBytes = null; 739 sNameLength = 0; 740 fromLength = 0; 741 tillLength = 0; 742 rtimeLength = 0; 743 nonceLength = 0; 744 eTypeLength = 0; 745 eTypeSeqLength = 0; 746 eTypeLengths = null; 747 addressesLength = 0; 748 encAuthzDataLength = 0; 749 additionalTicketLength = 0; 750 additionalTicketSeqLength = 0; 751 additionalTicketsLengths = null; 752 kdcReqBodySeqLength = 0; 753 kdcReqBodyLength = 0; 754 } 755 756 757 /** 758 * Pretty print the instance 759 */ 760 public String toString( String tabs ) 761 { 762 StringBuilder sb = new StringBuilder(); 763 764 if ( ( kdcOptions != null ) && ( kdcOptions.size() > 0 ) ) 765 { 766 sb.append( tabs ).append( "KDCOptions : " ).append( kdcOptions ).append( '\n' ); 767 } 768 769 if ( cName != null ) 770 { 771 sb.append( tabs ).append( "cname : " ).append( cName ).append( '\n' ); 772 } 773 774 sb.append( tabs ).append( "realm : " ).append( realm ).append( '\n' ); 775 776 if ( sName != null ) 777 { 778 sb.append( tabs ).append( "sname : " ).append( sName ).append( '\n' ); 779 } 780 781 if ( from != null ) 782 { 783 sb.append( tabs ).append( "from : " ).append( from ).append( '\n' ); 784 } 785 786 sb.append( tabs ).append( "till : " ).append( till ).append( '\n' ); 787 788 if ( rtime != null ) 789 { 790 sb.append( tabs ).append( "rtime : " ).append( rtime ).append( '\n' ); 791 } 792 793 sb.append( tabs ).append( "nonce : " ).append( nonce ).append( '\n' ); 794 795 sb.append( tabs ).append( "etype : " ); 796 boolean isFirst = true; 797 798 for ( EncryptionType encryptionType : eType ) 799 { 800 if ( isFirst ) 801 { 802 isFirst = false; 803 } 804 else 805 { 806 sb.append( " " ); 807 } 808 809 sb.append( encryptionType ); 810 } 811 812 if ( addresses != null ) 813 { 814 sb.append( '\n' ); 815 sb.append( tabs ).append( "addresses : " ); 816 isFirst = true; 817 818 for ( HostAddress hostAddress : addresses.getAddresses() ) 819 { 820 if ( isFirst ) 821 { 822 isFirst = false; 823 } 824 else 825 { 826 sb.append( " " ); 827 } 828 829 sb.append( hostAddress ); 830 } 831 } 832 833 if ( encAuthorizationData != null ) 834 { 835 sb.append( '\n' ); 836 sb.append( tabs ).append( "enc-authorization-data" ).append( encAuthorizationData ); 837 } 838 839 if ( !additionalTickets.isEmpty() ) 840 { 841 sb.append( '\n' ); 842 sb.append( tabs ).append( "Tickets : " ); 843 isFirst = true; 844 845 for ( Ticket ticket : additionalTickets ) 846 { 847 if ( isFirst ) 848 { 849 isFirst = false; 850 sb.append( '\n' ); 851 } 852 853 sb.append( ticket.toString( tabs + " " ) ); 854 } 855 } 856 857 return sb.toString(); 858 } 859 860 861 /** 862 * @see Object#toString() 863 */ 864 public String toString() 865 { 866 return toString( "" ); 867 } 868}