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.messages; 021 022 023import java.nio.BufferOverflowException; 024import java.nio.ByteBuffer; 025 026import org.apache.directory.api.asn1.EncoderException; 027import org.apache.directory.api.asn1.ber.tlv.BerValue; 028import org.apache.directory.api.asn1.ber.tlv.TLV; 029import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 030import org.apache.directory.api.util.Strings; 031import org.apache.directory.server.i18n.I18n; 032import org.apache.directory.shared.kerberos.KerberosConstants; 033import org.apache.directory.shared.kerberos.KerberosMessageType; 034import org.apache.directory.shared.kerberos.components.EncTicketPart; 035import org.apache.directory.shared.kerberos.components.EncryptedData; 036import org.apache.directory.shared.kerberos.components.PrincipalName; 037import org.apache.directory.shared.kerberos.exceptions.InvalidTicketException; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041 042/** 043 * Ticket message component as handed out by the ticket granting service. It will store 044 * the object described by the ASN.1 grammar : 045 * <pre> 046 * Ticket ::= [APPLICATION 1] SEQUENCE { 047 * tkt-vno [0] INTEGER (5), 048 * realm [1] Realm, 049 * sname [2] <PrincipalName>, 050 * enc-part [3] <EncryptedData> -- EncTicketPart 051 * } 052 * </pre> 053 * 054 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 055 */ 056public class Ticket extends KerberosMessage 057{ 058 /** The logger */ 059 private static final Logger LOG = LoggerFactory.getLogger( Ticket.class ); 060 061 /** Speedup for logs */ 062 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 063 064 /** Constant for the {@link Ticket} version number (5) */ 065 public static final int TICKET_VNO = KerberosConstants.KERBEROS_V5; 066 067 /** A storage for a byte array representation of the realm */ 068 private byte[] realmBytes; 069 070 /** The server principal name */ 071 private PrincipalName sName; 072 073 /** The server realm */ 074 private String realm; 075 076 /** The encoded part */ 077 private EncryptedData encPart; 078 079 /** The encoded ticket part, stored in its original form (not encoded) */ 080 private EncTicketPart encTicketPart; 081 082 // Storage for computed lengths 083 private int tktvnoLength; 084 private int realmLength; 085 private int sNameLength; 086 private int encPartLength; 087 private int ticketSeqLength; 088 private int ticketLength; 089 090 091 /** 092 * Creates a new instance of Ticket. 093 * 094 * @param sName The server principal 095 * @param encPart The encoded part 096 */ 097 public Ticket( PrincipalName sName, EncryptedData encPart ) throws InvalidTicketException 098 { 099 this( TICKET_VNO, sName, encPart ); 100 101 setSName( sName ); 102 } 103 104 105 /** 106 * Creates a new instance of Ticket. 107 */ 108 public Ticket() 109 { 110 super( KerberosMessageType.TICKET ); 111 } 112 113 114 /** 115 * Creates a new instance of Ticket. 116 * 117 * @param tktvno The Kerberos version number 118 * @param sName The server principal 119 * @param encPart The encoded part 120 */ 121 public Ticket( int tktvno, PrincipalName sName, EncryptedData encPart ) 122 { 123 super( tktvno, KerberosMessageType.TICKET ); 124 this.encPart = encPart; 125 setSName( sName ); 126 } 127 128 129 /** 130 * Returns the {@link EncryptedData}. 131 * 132 * @return The {@link EncryptedData}. 133 */ 134 public EncryptedData getEncPart() 135 { 136 return encPart; 137 } 138 139 140 /** 141 * Set the encrypted ticket part 142 * @param encPart the encrypted ticket part 143 */ 144 public void setEncPart( EncryptedData encPart ) 145 { 146 this.encPart = encPart; 147 } 148 149 150 /** 151 * Returns the server realm. 152 * 153 * @return The server realm. 154 */ 155 public String getRealm() 156 { 157 return realm; 158 } 159 160 161 /** 162 * Set the server realm 163 * @param realm the server realm 164 */ 165 public void setRealm( String realm ) 166 { 167 this.realm = realm; 168 } 169 170 171 /** 172 * Returns the server {@link PrincipalName}. 173 * 174 * @return The server {@link PrincipalName}. 175 */ 176 public PrincipalName getSName() 177 { 178 return sName; 179 } 180 181 182 /** 183 * Set the server principalName 184 * @param sName the server principalName 185 */ 186 public void setSName( PrincipalName sName ) 187 { 188 this.sName = sName; 189 } 190 191 192 /** 193 * Gets the Ticket Version number 194 * @return The ticket version number 195 */ 196 public int getTktVno() 197 { 198 return getProtocolVersionNumber(); 199 } 200 201 202 /** 203 * Sets the Ticket Version number 204 * @param tktVno The new version number 205 */ 206 public void setTktVno( int tktVno ) 207 { 208 setProtocolVersionNumber( tktVno ); 209 } 210 211 212 /** 213 * @return the encTicketPart 214 */ 215 public EncTicketPart getEncTicketPart() 216 { 217 return encTicketPart; 218 } 219 220 221 /** 222 * @param encTicketPart the encTicketPart to set 223 */ 224 public void setEncTicketPart( EncTicketPart encTicketPart ) 225 { 226 this.encTicketPart = encTicketPart; 227 } 228 229 230 /** 231 * Compute the Ticket length 232 * <pre> 233 * Ticket : 234 * 235 * 0x61 L1 Ticket [APPLICATION 1] 236 * | 237 * +--> 0x30 L2 Ticket SEQUENCE 238 * | 239 * +--> 0xA0 L3 tkt-vno tag 240 * | | 241 * | +--> 0x02 L3-1 tkt-vno (int, 5) 242 * | 243 * +--> 0xA1 L4 realm tag 244 * | | 245 * | +--> 0x1B L4-1 realm (KerberosString) 246 * | 247 * +--> 0xA2 L5 sname (PrincipalName) 248 * | 249 * +--> 0xA3 L6 enc-part (EncryptedData) 250 * </pre> 251 */ 252 public int computeLength() 253 { 254 // Compute the Ticket version length. 255 tktvnoLength = 1 + 1 + BerValue.getNbBytes( getProtocolVersionNumber() ); 256 257 // Compute the Ticket realm length. 258 realmBytes = Strings.getBytesUtf8( realm ); 259 realmLength = 1 + TLV.getNbBytes( realmBytes.length ) + realmBytes.length; 260 261 // Compute the principal length 262 sNameLength = sName.computeLength(); 263 264 // Compute the encrypted data 265 encPartLength = encPart.computeLength(); 266 267 // Compute the sequence size 268 ticketSeqLength = 269 1 + TLV.getNbBytes( tktvnoLength ) + tktvnoLength + 270 1 + TLV.getNbBytes( realmLength ) + realmLength + 271 1 + TLV.getNbBytes( sNameLength ) + sNameLength + 272 1 + TLV.getNbBytes( encPartLength ) + encPartLength; 273 274 // compute the global size 275 ticketLength = 1 + TLV.getNbBytes( ticketSeqLength ) + ticketSeqLength; 276 277 return 1 + TLV.getNbBytes( ticketLength ) + ticketLength; 278 } 279 280 281 /** 282 * Encode the Ticket message to a PDU. 283 * <pre> 284 * Ticket : 285 * 286 * 0x61 LL 287 * 0x30 LL 288 * 0xA0 LL tktvno 289 * 0xA1 LL realm 290 * 0xA2 LL 291 * sname (PrincipalName) 292 * 0xA3 LL 293 * enc-part (EncryptedData) 294 * </pre> 295 * @return The constructed PDU. 296 */ 297 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 298 { 299 if ( buffer == null ) 300 { 301 buffer = ByteBuffer.allocate( computeLength() ); 302 } 303 304 try 305 { 306 // The Ticket APPLICATION Tag 307 buffer.put( ( byte ) KerberosConstants.TICKET_TAG ); 308 buffer.put( TLV.getBytes( ticketLength ) ); 309 310 // The Ticket SEQUENCE Tag 311 buffer.put( UniversalTag.SEQUENCE.getValue() ); 312 buffer.put( TLV.getBytes( ticketSeqLength ) ); 313 314 // The tkt-vno Tag and value 315 buffer.put( ( byte ) KerberosConstants.TICKET_TKT_VNO_TAG ); 316 buffer.put( TLV.getBytes( tktvnoLength ) ); 317 BerValue.encode( buffer, getProtocolVersionNumber() ); 318 319 // The realm Tag and value 320 buffer.put( ( byte ) KerberosConstants.TICKET_REALM_TAG ); 321 buffer.put( TLV.getBytes( realmLength ) ); 322 buffer.put( UniversalTag.GENERAL_STRING.getValue() ); 323 buffer.put( TLV.getBytes( realmBytes.length ) ); 324 buffer.put( realmBytes ); 325 326 // The sname Tag and value 327 buffer.put( ( byte ) KerberosConstants.TICKET_SNAME_TAG ); 328 buffer.put( TLV.getBytes( sNameLength ) ); 329 sName.encode( buffer ); 330 331 // The encPartLength Tag and value 332 buffer.put( ( byte ) KerberosConstants.TICKET_ENC_PART_TAG ); 333 buffer.put( TLV.getBytes( encPartLength ) ); 334 encPart.encode( buffer ); 335 } 336 catch ( BufferOverflowException boe ) 337 { 338 LOG.error( I18n.err( I18n.ERR_137, 1 + TLV.getNbBytes( ticketLength ) + ticketLength, 339 buffer.capacity() ) ); 340 throw new EncoderException( I18n.err( I18n.ERR_138 ), boe ); 341 } 342 343 if ( IS_DEBUG ) 344 { 345 LOG.debug( "Ticket encoding : {}", Strings.dumpBytes( buffer.array() ) ); 346 LOG.debug( "Ticket initial value : {}", this ); 347 } 348 349 return buffer; 350 } 351 352 353 /** 354 * {@inheritDoc} 355 */ 356 @Override 357 public int hashCode() 358 { 359 final int prime = 31; 360 int result = 1; 361 result = prime * result + ( ( encPart == null ) ? 0 : encPart.hashCode() ); 362 result = prime * result + ( ( realm == null ) ? 0 : realm.hashCode() ); 363 result = prime * result + ( ( sName == null ) ? 0 : sName.hashCode() ); 364 return result; 365 } 366 367 368 /** 369 * {@inheritDoc} 370 */ 371 @Override 372 public boolean equals( Object obj ) 373 { 374 if ( this == obj ) 375 { 376 return true; 377 } 378 379 if ( !( obj instanceof Ticket ) ) 380 { 381 return false; 382 } 383 384 Ticket other = ( Ticket ) obj; 385 386 if ( encPart == null ) 387 { 388 if ( other.encPart != null ) 389 { 390 return false; 391 } 392 } 393 else if ( !encPart.equals( other.encPart ) ) 394 { 395 return false; 396 } 397 398 if ( realm == null ) 399 { 400 if ( other.realm != null ) 401 { 402 return false; 403 } 404 } 405 else if ( !realm.equals( other.realm ) ) 406 { 407 return false; 408 } 409 410 if ( sName == null ) 411 { 412 if ( other.sName != null ) 413 { 414 return false; 415 } 416 } 417 else if ( !sName.equals( other.sName ) ) 418 { 419 return false; 420 } 421 422 return true; 423 } 424 425 426 /** 427 * Pretty print the instance 428 */ 429 public String toString( String tabs ) 430 { 431 StringBuilder sb = new StringBuilder(); 432 433 sb.append( tabs ).append( "Ticket :\n" ); 434 sb.append( tabs ).append( " tkt-vno : " ).append( getProtocolVersionNumber() ).append( "\n" ); 435 sb.append( tabs ).append( " realm : " ).append( realm ).append( "\n" ); 436 sb.append( tabs ).append( " sname : " ).append( sName ).append( "\n" ); 437 sb.append( tabs ).append( " enc-part : " ).append( encPart ).append( "\n" ); 438 439 return sb.toString(); 440 } 441 442 443 /** 444 * @see Object#toString() 445 */ 446 public String toString() 447 { 448 return toString( "" ); 449 } 450}