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