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    import java.nio.BufferOverflowException;
024    import java.nio.ByteBuffer;
025    
026    import org.apache.directory.server.kerberos.shared.messages.value.types.AuthorizationType;
027    import org.apache.directory.shared.asn1.AbstractAsn1Object;
028    import org.apache.directory.shared.asn1.ber.tlv.TLV;
029    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
030    import org.apache.directory.shared.asn1.ber.tlv.Value;
031    import org.apache.directory.shared.asn1.codec.EncoderException;
032    import org.apache.directory.shared.ldap.util.StringTools;
033    import org.slf4j.Logger;
034    import org.slf4j.LoggerFactory;
035    
036    
037    /**
038     * A single AuthorizationData
039     * 
040     * The ASN.1 grammar is :
041     * -- NOTE: AuthorizationData is always used as an OPTIONAL field and
042     * -- should not be empty.
043     * AuthorizationDataEntry       ::= SEQUENCE {
044     *        ad-type         [0] Int32,
045     *        ad-data         [1] OCTET STRING
046     * }
047     *  
048     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049     * @version $Rev: 587531 $, $Date: 2007-10-23 17:59:10 +0300 (Tue, 23 Oct 2007) $
050     */
051    public class AuthorizationDataEntry extends AbstractAsn1Object
052    {
053        /** The logger */
054        private static final Logger log = LoggerFactory.getLogger( AuthorizationDataEntry.class );
055    
056        /** Speedup for logs */
057        private static final boolean IS_DEBUG = log.isDebugEnabled();
058    
059        /** The Authorization type. One of :
060         * DER encoding of AD-IF-RELEVANT        1
061         * DER encoding of AD-KDCIssued          4
062         * DER encoding of AD-AND-OR             5
063         * DER encoding of AD-MANDATORY-FOR-KDC  8 
064         **/
065        private AuthorizationType adType;
066    
067        /** The data, encrypted */
068        private byte[] adData;
069    
070        // Storage for computed lengths
071        private transient int adTypeLength;
072        private transient int adDataLength;
073        private transient int authorizationDataEntryLength;
074    
075    
076        /**
077         * Creates a new instance of AuthorizationDataEntry.
078         */
079        public AuthorizationDataEntry()
080        {
081        }
082    
083        
084        /**
085         * Creates a new instance of AuthorizationDataEntry.
086         *
087         * @param adType The authorizationType
088         * @param adData The authorization data
089         */
090        public AuthorizationDataEntry( AuthorizationType adType, byte[] adData )
091        {
092            this.adType = adType;
093            this.adData = adData;
094        }
095    
096    
097        /**
098         * Returns the raw bytes of the authorization data.
099         *
100         * @return The raw bytes of the authorization data.
101         */
102        public byte[] getAdData()
103        {
104            return adData;
105        }
106    
107    
108        /**
109         * Set the authorization data
110         * 
111         * @param adData The data
112         */
113        public void setAdData( byte[] adData ) 
114        {
115            this.adData = adData;
116        }
117    
118        
119        /**
120         * Returns the {@link AuthorizationType}.
121         *
122         * @return The {@link AuthorizationType}.
123         */
124        public AuthorizationType getAdType()
125        {
126            return adType;
127        }
128    
129    
130        /**
131         * Set the authorization type
132         * @param adType The authorization type
133         */
134        public void setAdType( int adType ) 
135        {
136            this.adType = AuthorizationType.getTypeByOrdinal( adType );
137        }
138    
139        
140        /**
141         * Set the authorization type
142         * @param adType The authorization type
143         */
144        public void setAdType( AuthorizationType adType ) 
145        {
146            this.adType = adType;
147        }
148    
149        
150        /**
151         * Compute the AuthorizationDataEntry length
152         * 
153         * AuthorizationDataEntry :
154         * 
155         * 0x30 L1 AuthorizationDataEntry
156         *  |
157         *  +--> 0xA0 L2 adType tag
158         *  |     |
159         *  |     +--> 0x02 L2-1 adType (int)
160         *  |
161         *  +--> 0xA1 L3 adData tag
162         *        |
163         *        +--> 0x04 L3-1 adData (OCTET STRING)
164         *        
165         *  where L1 = L2 + lenght(0xA0) + length(L2) +
166         *             L3 + lenght(0xA1) + length(L3) 
167         *  and
168         *  L2 = L2-1 + length(0x02) + length( L2-1) 
169         *  L3 = L3-1 + length(0x04) + length( L3-1) 
170         */
171        public int computeLength()
172        {
173            // Compute the adType. The Length will always be contained in 1 byte
174            adTypeLength = 1 + 1 + Value.getNbBytes( adType.getOrdinal() );
175            authorizationDataEntryLength = 1 + TLV.getNbBytes( adTypeLength ) + adTypeLength;
176    
177            // Compute the keyValue
178            if ( adData == null )
179            {
180                adDataLength = 1 + 1;
181            }
182            else
183            {
184                adDataLength = 1 + TLV.getNbBytes( adData.length ) + adData.length;
185            }
186    
187            authorizationDataEntryLength += 1 + TLV.getNbBytes( adDataLength ) + adDataLength;
188    
189            // Compute the whole sequence length
190            int authorizationDataEntrySeqLength = 1 + Value.getNbBytes( authorizationDataEntryLength )
191                + authorizationDataEntryLength;
192    
193            return authorizationDataEntrySeqLength;
194    
195        }
196    
197    
198        /**
199         * Encode the AuthorizationDataEntry message to a PDU. 
200         * 
201         * AuthorizationDataEntry :
202         * 
203         * 0x30 LL
204         *   0xA0 LL 
205         *     0x02 0x01 adType
206         *   0xA1 LL 
207         *     0x04 LL adData
208         * 
209         * @param buffer The buffer where to put the PDU. It should have been allocated
210         * before, with the right size.
211         * @return The constructed PDU.
212         */
213        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
214        {
215            if ( buffer == null )
216            {
217                throw new EncoderException( "Cannot put a PDU in a null buffer !" );
218            }
219    
220            try
221            {
222                // The AuthorizationDataEntry SEQ Tag
223                buffer.put( UniversalTag.SEQUENCE_TAG );
224                buffer.put( TLV.getBytes( authorizationDataEntryLength ) );
225    
226                // The adType, first the tag, then the value
227                buffer.put( ( byte ) 0xA0 );
228                buffer.put( TLV.getBytes( adTypeLength ) );
229                Value.encode( buffer, adType.getOrdinal() );
230    
231                // The adData, first the tag, then the value
232                buffer.put( ( byte ) 0xA1 );
233                buffer.put( TLV.getBytes( adDataLength ) );
234                Value.encode( buffer, adData );
235            }
236            catch ( BufferOverflowException boe )
237            {
238                log
239                    .error(
240                        "Cannot encode the AuthorizationDataEntry object, the PDU size is {} when only {} bytes has been allocated",
241                        1 + TLV.getNbBytes( authorizationDataEntryLength ) + authorizationDataEntryLength, buffer
242                            .capacity() );
243                throw new EncoderException( "The PDU buffer size is too small !" );
244            }
245    
246            if ( IS_DEBUG )
247            {
248                log.debug( "AuthorizationDataEntry encoding : {}", StringTools.dumpBytes( buffer.array() ) );
249                log.debug( "AuthorizationDataEntry initial value : {}", toString() );
250            }
251    
252            return buffer;
253        }
254    
255    
256        /**
257         * @see Object#toString()
258         */
259        public String toString()
260        {
261            return toString( "    " );
262        }
263    
264    
265        /**
266         * @see Object#toString()
267         */
268        public String toString( String tabs )
269        {
270            StringBuilder sb = new StringBuilder();
271    
272            sb.append( tabs ).append( "AuthorizationDataEntry : {\n" );
273            sb.append( tabs ).append( "    ad-type: " ).append( adType ).append( '\n' );
274    
275            sb.append( tabs ).append( "    ad-data: " ).append( StringTools.dumpBytes( adData ) )
276                .append( "\n" + tabs + "}" );
277    
278            return sb.toString();
279        }
280    }