blob: f4bd7719a26e3622ace0bc432b85756e2e35a1a9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.shared.kerberos.messages;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import org.apache.directory.api.asn1.EncoderException;
import org.apache.directory.api.asn1.ber.tlv.BerValue;
import org.apache.directory.api.asn1.ber.tlv.TLV;
import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
import org.apache.directory.api.util.Strings;
import org.apache.directory.server.i18n.I18n;
import org.apache.directory.shared.kerberos.KerberosConstants;
import org.apache.directory.shared.kerberos.KerberosMessageType;
import org.apache.directory.shared.kerberos.components.EncTicketPart;
import org.apache.directory.shared.kerberos.components.EncryptedData;
import org.apache.directory.shared.kerberos.components.PrincipalName;
import org.apache.directory.shared.kerberos.exceptions.InvalidTicketException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Ticket message component as handed out by the ticket granting service. It will store
* the object described by the ASN.1 grammar :
* <pre>
* Ticket ::= [APPLICATION 1] SEQUENCE {
* tkt-vno [0] INTEGER (5),
* realm [1] Realm,
* sname [2] <PrincipalName>,
* enc-part [3] <EncryptedData> -- EncTicketPart
* }
* </pre>
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class Ticket extends KerberosMessage
{
/** The logger */
private static final Logger LOG = LoggerFactory.getLogger( Ticket.class );
/** Speedup for logs */
private static final boolean IS_DEBUG = LOG.isDebugEnabled();
/** Constant for the {@link Ticket} version number (5) */
public static final int TICKET_VNO = KerberosConstants.KERBEROS_V5;
/** A storage for a byte array representation of the realm */
private byte[] realmBytes;
/** The server principal name */
private PrincipalName sName;
/** The server realm */
private String realm;
/** The encoded part */
private EncryptedData encPart;
/** The encoded ticket part, stored in its original form (not encoded) */
private EncTicketPart encTicketPart;
// Storage for computed lengths
private int tktvnoLength;
private int realmLength;
private int sNameLength;
private int encPartLength;
private int ticketSeqLength;
private int ticketLength;
/**
* Creates a new instance of Ticket.
*
* @param serverPrincipal The server principal
* @param encPart The encoded part
*/
public Ticket( PrincipalName sName, EncryptedData encPart ) throws InvalidTicketException
{
this( TICKET_VNO, sName, encPart );
setSName( sName );
}
/**
* Creates a new instance of Ticket.
*/
public Ticket()
{
super( KerberosMessageType.TICKET );
}
/**
* Creates a new instance of Ticket.
*
* @param tktvno The Kerberos version number
* @param serverPrincipal The server principal
* @param encPart The encoded part
*/
public Ticket( int tktvno, PrincipalName sName, EncryptedData encPart ) throws InvalidTicketException
{
super( tktvno, KerberosMessageType.TICKET );
this.encPart = encPart;
setSName( sName );
}
/**
* Returns the {@link EncryptedData}.
*
* @return The {@link EncryptedData}.
*/
public EncryptedData getEncPart()
{
return encPart;
}
/**
* Set the encrypted ticket part
* @param encPart the encrypted ticket part
*/
public void setEncPart( EncryptedData encPart )
{
this.encPart = encPart;
}
/**
* Returns the server realm.
*
* @return The server realm.
*/
public String getRealm()
{
return realm;
}
/**
* Set the server realm
* @param realm the server realm
*/
public void setRealm( String realm )
{
this.realm = realm;
}
/**
* Returns the server {@link PrincipalName}.
*
* @return The server {@link PrincipalName}.
*/
public PrincipalName getSName()
{
return sName;
}
/**
* Set the server principalName
* @param sName the server principalName
*/
public void setSName( PrincipalName sName )
{
this.sName = sName;
}
/**
* Gets the Ticket Version number
* @return The ticket version number
*/
public int getTktVno()
{
return getProtocolVersionNumber();
}
/**
* Sets the Ticket Version number
* @param tktVno The new version number
*/
public void setTktVno( int tktVno )
{
setProtocolVersionNumber( tktVno );
}
/**
* @return the encTicketPart
*/
public EncTicketPart getEncTicketPart()
{
return encTicketPart;
}
/**
* @param encTicketPart the encTicketPart to set
*/
public void setEncTicketPart( EncTicketPart encTicketPart )
{
this.encTicketPart = encTicketPart;
}
/**
* Compute the Ticket length
* <pre>
* Ticket :
*
* 0x61 L1 Ticket [APPLICATION 1]
* |
* +--> 0x30 L2 Ticket SEQUENCE
* |
* +--> 0xA0 L3 tkt-vno tag
* | |
* | +--> 0x02 L3-1 tkt-vno (int, 5)
* |
* +--> 0xA1 L4 realm tag
* | |
* | +--> 0x1B L4-1 realm (KerberosString)
* |
* +--> 0xA2 L5 sname (PrincipalName)
* |
* +--> 0xA3 L6 enc-part (EncryptedData)
* </pre>
*/
public int computeLength()
{
// Compute the Ticket version length.
tktvnoLength = 1 + 1 + BerValue.getNbBytes( getProtocolVersionNumber() );
// Compute the Ticket realm length.
realmBytes = Strings.getBytesUtf8( realm );
realmLength = 1 + TLV.getNbBytes( realmBytes.length ) + realmBytes.length;
// Compute the principal length
sNameLength = sName.computeLength();
// Compute the encrypted data
encPartLength = encPart.computeLength();
// Compute the sequence size
ticketSeqLength =
1 + TLV.getNbBytes( tktvnoLength ) + tktvnoLength +
1 + TLV.getNbBytes( realmLength ) + realmLength +
1 + TLV.getNbBytes( sNameLength ) + sNameLength +
1 + TLV.getNbBytes( encPartLength ) + encPartLength;
// compute the global size
ticketLength = 1 + TLV.getNbBytes( ticketSeqLength ) + ticketSeqLength;
return 1 + TLV.getNbBytes( ticketLength ) + ticketLength;
}
/**
* Encode the Ticket message to a PDU.
* <pre>
* Ticket :
*
* 0x61 LL
* 0x30 LL
* 0xA0 LL tktvno
* 0xA1 LL realm
* 0xA2 LL
* sname (PrincipalName)
* 0xA3 LL
* enc-part (EncryptedData)
* </pre>
* @return The constructed PDU.
*/
public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
{
if ( buffer == null )
{
buffer = ByteBuffer.allocate( computeLength() );
}
try
{
// The Ticket APPLICATION Tag
buffer.put( ( byte ) KerberosConstants.TICKET_TAG );
buffer.put( TLV.getBytes( ticketLength ) );
// The Ticket SEQUENCE Tag
buffer.put( UniversalTag.SEQUENCE.getValue() );
buffer.put( TLV.getBytes( ticketSeqLength ) );
// The tkt-vno Tag and value
buffer.put( ( byte ) KerberosConstants.TICKET_TKT_VNO_TAG );
buffer.put( TLV.getBytes( tktvnoLength ) );
BerValue.encode( buffer, getProtocolVersionNumber() );
// The realm Tag and value
buffer.put( ( byte ) KerberosConstants.TICKET_REALM_TAG );
buffer.put( TLV.getBytes( realmLength ) );
buffer.put( UniversalTag.GENERAL_STRING.getValue() );
buffer.put( TLV.getBytes( realmBytes.length ) );
buffer.put( realmBytes );
// The sname Tag and value
buffer.put( ( byte ) KerberosConstants.TICKET_SNAME_TAG );
buffer.put( TLV.getBytes( sNameLength ) );
sName.encode( buffer );
// The encPartLength Tag and value
buffer.put( ( byte ) KerberosConstants.TICKET_ENC_PART_TAG );
buffer.put( TLV.getBytes( encPartLength ) );
encPart.encode( buffer );
}
catch ( BufferOverflowException boe )
{
LOG.error( I18n.err( I18n.ERR_137, 1 + TLV.getNbBytes( ticketLength ) + ticketLength,
buffer.capacity() ) );
throw new EncoderException( I18n.err( I18n.ERR_138 ) );
}
if ( IS_DEBUG )
{
LOG.debug( "Ticket encoding : {}", Strings.dumpBytes( buffer.array() ) );
LOG.debug( "Ticket initial value : {}", toString() );
}
return buffer;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ( ( encPart == null ) ? 0 : encPart.hashCode() );
result = prime * result + ( ( realm == null ) ? 0 : realm.hashCode() );
result = prime * result + ( ( sName == null ) ? 0 : sName.hashCode() );
return result;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals( Object obj )
{
if ( this == obj )
{
return true;
}
if ( obj == null )
{
return false;
}
Ticket other = ( Ticket ) obj;
if ( encPart == null )
{
if ( other.encPart != null )
{
return false;
}
}
else if ( !encPart.equals( other.encPart ) )
{
return false;
}
if ( realm == null )
{
if ( other.realm != null )
{
return false;
}
}
else if ( !realm.equals( other.realm ) )
{
return false;
}
if ( sName == null )
{
if ( other.sName != null )
{
return false;
}
}
else if ( !sName.equals( other.sName ) )
{
return false;
}
return true;
}
/**
* Pretty print the instance
*/
public String toString( String tabs )
{
StringBuilder sb = new StringBuilder();
sb.append( tabs ).append( "Ticket :\n" );
sb.append( tabs ).append( " tkt-vno : " ).append( getProtocolVersionNumber() ).append( "\n" );
sb.append( tabs ).append( " realm : " ).append( realm ).append( "\n" );
sb.append( tabs ).append( " sname : " ).append( sName ).append( "\n" );
sb.append( tabs ).append( " enc-part : " ).append( encPart ).append( "\n" );
return sb.toString();
}
/**
* @see Object#toString()
*/
public String toString()
{
return toString( "" );
}
}