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
021package org.apache.directory.shared.kerberos.components;
022
023
024import java.nio.BufferOverflowException;
025import java.nio.ByteBuffer;
026import java.util.ArrayList;
027import java.util.List;
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.codec.types.AuthorizationType;
038import org.slf4j.Logger;
039import org.slf4j.LoggerFactory;
040
041
042/**
043 * A structure to hold the authorization data.
044 * 
045 * <pre>
046 * AuthorizationData      ::= SEQUENCE OF SEQUENCE {
047 *               ad-type  [0] Int32,
048 *               ad-data  [1] OCTET STRING
049 * }
050 *</pre>
051 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
052 */
053public class AuthorizationData implements Asn1Object
054{
055    /** The list of AuthorizationData elements */
056    private List<AuthorizationDataEntry> authorizationData = new ArrayList<>();
057
058    /** The current AD being processed */
059    private AuthorizationDataEntry currentAD;
060
061    /** The logger */
062    private static final Logger LOG = LoggerFactory.getLogger( EncryptedData.class );
063
064    /** Speedup for logs */
065    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
066
067    // Storage for computed lengths
068    private int adTypeTagLen[];
069    private int adDataTagLen[];
070    private int authorizationDataSeqLen[];
071    private int authorizationDataSeqSeqLen;
072
073
074    /**
075     * Creates a new set of AuthorizationData
076     */
077    public AuthorizationData()
078    {
079    }
080
081
082    /**
083     * Compute the AuthorizationData length
084     * <pre>
085     * 0x30 L1 AuthorizationData sequence
086     *  |
087     *  +-- 0x30 L2 The AD sequence
088     *       |
089     *       +--&gt; 0xA0 L3 adType tag
090     *       |     |
091     *       |     +--&gt; 0x02 L3-1 adType (int)
092     *       |
093     *       +--&gt; 0xA1 L4 adData tag
094     *             |
095     *             +--&gt; 0x04 L4-1 adData (OCTET STRING)
096     * </pre>
097     */
098    @Override
099    public int computeLength()
100    {
101        int i = 0;
102        authorizationDataSeqLen = new int[authorizationData.size()];
103        adTypeTagLen = new int[authorizationData.size()];
104        adDataTagLen = new int[authorizationData.size()];
105        authorizationDataSeqSeqLen = 0;
106
107        for ( AuthorizationDataEntry ad : authorizationData )
108        {
109            int adTypeLen = BerValue.getNbBytes( ad.getAdType().getValue() );
110            adTypeTagLen[i] = 1 + TLV.getNbBytes( adTypeLen ) + adTypeLen;
111            adDataTagLen[i] = 1 + TLV.getNbBytes( ad.getAdDataRef().length ) + ad.getAdDataRef().length;
112
113            authorizationDataSeqLen[i] = 1 + TLV.getNbBytes( adTypeTagLen[i] ) + adTypeTagLen[i] +
114                1 + TLV.getNbBytes( adDataTagLen[i] ) + adDataTagLen[i];
115
116            authorizationDataSeqSeqLen += 1 + TLV.getNbBytes( authorizationDataSeqLen[i] ) + authorizationDataSeqLen[i];
117            i++;
118        }
119
120        return 1 + TLV.getNbBytes( authorizationDataSeqSeqLen ) + authorizationDataSeqSeqLen;
121    }
122
123
124    /**
125     * Encode the EncryptedData message to a PDU.
126     * 
127     * @param buffer The buffer where to put the PDU. It should have been allocated
128     * before, with the right size.
129     * @return The constructed PDU.
130     */
131    @Override
132    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
133    {
134        if ( buffer == null )
135        {
136            throw new EncoderException( I18n.err( I18n.ERR_148 ) );
137        }
138
139        try
140        {
141            // The AuthorizationData SEQ OF Tag
142            buffer.put( UniversalTag.SEQUENCE.getValue() );
143            buffer.put( TLV.getBytes( authorizationDataSeqSeqLen ) );
144
145            int i = 0;
146
147            for ( AuthorizationDataEntry ad : authorizationData )
148            {
149                buffer.put( UniversalTag.SEQUENCE.getValue() );
150                buffer.put( TLV.getBytes( authorizationDataSeqLen[i] ) );
151
152                // the adType
153                buffer.put( ( byte ) KerberosConstants.AUTHORIZATION_DATA_ADTYPE_TAG );
154                buffer.put( TLV.getBytes( adTypeTagLen[i] ) );
155                BerValue.encode( buffer, ad.getAdType().getValue() );
156
157                // the adData
158                buffer.put( ( byte ) KerberosConstants.AUTHORIZATION_DATA_ADDATA_TAG );
159                buffer.put( TLV.getBytes( adDataTagLen[i] ) );
160                BerValue.encode( buffer, ad.getAdDataRef() );
161
162                i++;
163            }
164        }
165        catch ( BufferOverflowException boe )
166        {
167            LOG.error( I18n.err( I18n.ERR_139, 1 + TLV.getNbBytes( authorizationDataSeqSeqLen )
168                + authorizationDataSeqSeqLen, buffer.capacity() ) );
169            throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
170        }
171
172        if ( IS_DEBUG )
173        {
174            LOG.debug( "AuthorizationData encoding : {}", Strings.dumpBytes( buffer.array() ) );
175            LOG.debug( "AuthorizationData initial value : {}", this );
176        }
177
178        return buffer;
179    }
180
181
182    /**
183     * @return the currentAD type
184     */
185    public AuthorizationType getCurrentAdType()
186    {
187        return currentAD.getAdType();
188    }
189
190
191    /**
192     * Set the current AD type
193     */
194    public void setCurrentAdType( AuthorizationType adType )
195    {
196        currentAD.setAdType( adType );
197    }
198
199
200    /**
201     * @return the currentAD data
202     */
203    public byte[] getCurrentAdData()
204    {
205        return currentAD.getAdData();
206    }
207
208
209    /**
210     * Set the current AD data
211     */
212    public void setCurrentAdData( byte[] adData )
213    {
214        currentAD.setAdData( adData );
215    }
216
217
218    /**
219     * @return the currentAD
220     */
221    public AuthorizationDataEntry getCurrentAD()
222    {
223        return currentAD;
224    }
225
226
227    /**
228     * Create a new currentAD
229     */
230    public void createNewAD()
231    {
232        currentAD = new AuthorizationDataEntry();
233        authorizationData.add( currentAD );
234    }
235
236
237    /**
238     * Add a new AuthorizationDataEntry
239     */
240    public void addEntry( AuthorizationDataEntry entry )
241    {
242        authorizationData.add( entry );
243    }
244
245
246    /**
247     * @return the authorizationData
248     */
249    public List<AuthorizationDataEntry> getAuthorizationData()
250    {
251        return authorizationData;
252    }
253
254
255    /**
256     * {@inheritDoc}
257     */
258    @Override
259    public int hashCode()
260    {
261        final int prime = 31;
262        int result = 1;
263        result = prime * result + ( ( authorizationData == null ) ? 0 : authorizationData.hashCode() );
264        result = prime * result + ( ( currentAD == null ) ? 0 : currentAD.hashCode() );
265        return result;
266    }
267
268
269    /**
270     * {@inheritDoc}
271     */
272    @Override
273    public boolean equals( Object obj )
274    {
275        if ( this == obj )
276        {
277            return true;
278        }
279
280        if ( !( obj instanceof AuthorizationData ) )
281        {
282            return false;
283        }
284
285        AuthorizationData other = ( AuthorizationData ) obj;
286
287        if ( authorizationData == null )
288        {
289            if ( other.authorizationData != null )
290            {
291                return false;
292            }
293        }
294        else if ( !authorizationData.equals( other.authorizationData ) )
295        {
296            return false;
297        }
298
299        if ( currentAD == null )
300        {
301            if ( other.currentAD != null )
302            {
303                return false;
304            }
305        }
306        else if ( !currentAD.equals( other.currentAD ) )
307        {
308            return false;
309        }
310
311        return true;
312    }
313
314
315    /**
316     * @see Object#toString()
317     */
318    public String toString( String tabs )
319    {
320        StringBuilder sb = new StringBuilder();
321
322        sb.append( tabs ).append( "AuthorizationData : \n" );
323
324        for ( AuthorizationDataEntry ad : authorizationData )
325        {
326            sb.append( ad.toString( tabs + "    " ) );
327        }
328
329        return sb.toString();
330    }
331
332
333    /**
334     * @see Object#toString()
335     */
336    public String toString()
337    {
338        return toString( "" );
339    }
340}