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.api.ldap.codec.decorators;
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.i18n.I18n;
030import org.apache.directory.api.ldap.codec.api.LdapApiService;
031import org.apache.directory.api.ldap.codec.api.LdapConstants;
032import org.apache.directory.api.ldap.model.message.BindRequest;
033import org.apache.directory.api.ldap.model.message.Control;
034import org.apache.directory.api.ldap.model.name.Dn;
035import org.apache.directory.api.util.Strings;
036
037
038/**
039 * A decorator for the BindRequest message
040 *
041 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
042 */
043public class BindRequestDecorator extends SingleReplyRequestDecorator<BindRequest> implements BindRequest
044{
045    /** The bind request length */
046    private int bindRequestLength;
047
048    /** The SASL Mechanism length */
049    private int saslMechanismLength;
050
051    /** The SASL credentials length */
052    private int saslCredentialsLength;
053
054    /** The bytes containing the Dn */
055    private byte[] dnBytes;
056
057    /** The bytes containing the Name */
058    private byte[] nameBytes;
059
060    /** The bytes containing the SaslMechanism */
061    private byte[] mechanismBytes;
062
063
064    /**
065     * Makes a BindRequest a MessageDecorator.
066     *
067     * @param decoratedMessage the decorated BindRequests.
068     */
069    public BindRequestDecorator( LdapApiService codec, BindRequest decoratedMessage )
070    {
071        super( codec, decoratedMessage );
072    }
073
074
075    /**
076     * Stores the encoded length for the BindRequest
077     * @param bindRequestLength The encoded length
078     */
079    public void setBindRequestLength( int bindRequestLength )
080    {
081        this.bindRequestLength = bindRequestLength;
082    }
083
084
085    /**
086     * @return The encoded BindRequest's length
087     */
088    public int getBindRequestLength()
089    {
090        return bindRequestLength;
091    }
092
093
094    /**
095     * Stores the encoded length for the SaslCredentials
096     * @param saslCredentialsLength The encoded length
097     */
098    public void setSaslCredentialsLength( int saslCredentialsLength )
099    {
100        this.saslCredentialsLength = saslCredentialsLength;
101    }
102
103
104    /**
105     * @return The encoded SaslCredentials's length
106     */
107    public int getSaslCredentialsLength()
108    {
109        return saslCredentialsLength;
110    }
111
112
113    /**
114     * Stores the encoded length for the Mechanism
115     * @param saslMechanismLength The encoded length
116     */
117    public void setSaslMechanismLength( int saslMechanismLength )
118    {
119        this.saslMechanismLength = saslMechanismLength;
120    }
121
122
123    /**
124     * @return The encoded SaslMechanism's length
125     */
126    public int getSaslMechanismLength()
127    {
128        return saslMechanismLength;
129    }
130
131
132    /**
133     * {@inheritDoc}
134     */
135    public BindRequest setMessageId( int messageId )
136    {
137        super.setMessageId( messageId );
138
139        return this;
140    }
141
142
143    /**
144     * {@inheritDoc}
145     */
146    public BindRequest addControl( Control control )
147    {
148        return ( BindRequest ) super.addControl( control );
149    }
150
151
152    /**
153     * {@inheritDoc}
154     */
155    public BindRequest addAllControls( Control[] controls )
156    {
157        return ( BindRequest ) super.addAllControls( controls );
158    }
159
160
161    /**
162     * {@inheritDoc}
163     */
164    public BindRequest removeControl( Control control )
165    {
166        return ( BindRequest ) super.removeControl( control );
167    }
168
169
170    //-------------------------------------------------------------------------
171    // The BindRequest methods
172    //-------------------------------------------------------------------------
173
174    /**
175     * {@inheritDoc}
176     */
177    public boolean isSimple()
178    {
179        return getDecorated().isSimple();
180    }
181
182
183    /**
184     * {@inheritDoc}
185     */
186    public boolean getSimple()
187    {
188        return getDecorated().getSimple();
189    }
190
191
192    /**
193     * {@inheritDoc}
194     */
195    public BindRequest setSimple( boolean isSimple )
196    {
197        getDecorated().setSimple( isSimple );
198
199        return this;
200    }
201
202
203    /**
204     * {@inheritDoc}
205     */
206    public byte[] getCredentials()
207    {
208        return getDecorated().getCredentials();
209    }
210
211
212    /**
213     * {@inheritDoc}
214     */
215    public BindRequest setCredentials( String credentials )
216    {
217        getDecorated().setCredentials( credentials );
218
219        return this;
220    }
221
222
223    /**
224     * {@inheritDoc}
225     */
226    public BindRequest setCredentials( byte[] credentials )
227    {
228        getDecorated().setCredentials( credentials );
229
230        return this;
231    }
232
233
234    /**
235     * {@inheritDoc}
236     */
237    public String getName()
238    {
239        return getDecorated().getName();
240    }
241
242
243    /**
244     * {@inheritDoc}
245     */
246    public BindRequest setName( String name )
247    {
248        getDecorated().setName( name );
249
250        return this;
251    }
252
253
254    /**
255     * {@inheritDoc}
256     */
257    public Dn getDn()
258    {
259        return getDecorated().getDn();
260    }
261
262
263    /**
264     * {@inheritDoc}
265     */
266    public BindRequest setDn( Dn dn )
267    {
268        getDecorated().setDn( dn );
269
270        return this;
271    }
272
273
274    /**
275     * {@inheritDoc}
276     */
277    public boolean isVersion3()
278    {
279        return getDecorated().isVersion3();
280    }
281
282
283    /**
284     * {@inheritDoc}
285     */
286    public boolean getVersion3()
287    {
288        return getDecorated().getVersion3();
289    }
290
291
292    /**
293     * {@inheritDoc}
294     */
295    public BindRequest setVersion3( boolean isVersion3 )
296    {
297        getDecorated().setVersion3( isVersion3 );
298
299        return this;
300    }
301
302
303    /**
304     * {@inheritDoc}
305     */
306    public String getSaslMechanism()
307    {
308        return getDecorated().getSaslMechanism();
309    }
310
311
312    /**
313     * {@inheritDoc}
314     */
315    public BindRequest setSaslMechanism( String saslMechanism )
316    {
317        getDecorated().setSaslMechanism( saslMechanism );
318
319        return this;
320    }
321
322
323    //-------------------------------------------------------------------------
324    // The Decorator methods
325    //-------------------------------------------------------------------------
326    /**
327     * Compute the BindRequest length
328     * 
329     * BindRequest :
330     * <pre>
331     * 0x60 L1
332     *   |
333     *   +--> 0x02 0x01 (1..127) version
334     *   +--> 0x04 L2 name
335     *   +--> authentication
336     * 
337     * L2 = Length(name)
338     * L3/4 = Length(authentication)
339     * Length(BindRequest) = Length(0x60) + Length(L1) + L1 + Length(0x02) + 1 + 1 +
340     *      Length(0x04) + Length(L2) + L2 + Length(authentication)
341     * </pre>
342     */
343    public int computeLength()
344    {
345        int bindRequestLength = 1 + 1 + 1; // Initialized with version
346
347        Dn dn = getDn();
348
349        if ( !Dn.isNullOrEmpty( dn ) )
350        {
351            // A DN has been provided
352            dnBytes = Strings.getBytesUtf8( dn.getName() );
353            int dnLength = dnBytes.length;
354
355            bindRequestLength += 1 + TLV.getNbBytes( dnLength ) + dnLength;
356        }
357        else
358        {
359            // No DN has been provided, let's use the name as a string instead
360            String name = getName();
361
362            if ( Strings.isEmpty( name ) )
363            {
364                name = "";
365            }
366
367            nameBytes = Strings.getBytesUtf8( name );
368            int nameLength = nameBytes.length;
369
370            bindRequestLength += 1 + TLV.getNbBytes( nameLength ) + nameLength;
371        }
372
373        byte[] credentials = getCredentials();
374
375        // The authentication
376        if ( isSimple() )
377        {
378            // Compute a SimpleBind operation
379            if ( credentials != null )
380            {
381                bindRequestLength += 1 + TLV.getNbBytes( credentials.length ) + credentials.length;
382            }
383            else
384            {
385                bindRequestLength += 1 + 1;
386            }
387        }
388        else
389        {
390            mechanismBytes = Strings.getBytesUtf8( getSaslMechanism() );
391            saslMechanismLength = 1 + TLV.getNbBytes( mechanismBytes.length ) + mechanismBytes.length;
392
393            if ( credentials != null )
394            {
395                saslCredentialsLength = 1 + TLV.getNbBytes( credentials.length ) + credentials.length;
396            }
397
398            int saslLength = 1 + TLV.getNbBytes( saslMechanismLength + saslCredentialsLength ) + saslMechanismLength
399                + saslCredentialsLength;
400
401            bindRequestLength += saslLength;
402        }
403
404        setBindRequestLength( bindRequestLength );
405
406        // Return the result.
407        return 1 + TLV.getNbBytes( bindRequestLength ) + bindRequestLength;
408    }
409
410
411    /**
412     * Encode the BindRequest message to a PDU.
413     * 
414     * BindRequest :
415     * <pre>
416     * 0x60 LL
417     *   0x02 LL version         0x80 LL simple
418     *   0x04 LL name           /
419     *   authentication.encode()
420     *                          \ 0x83 LL mechanism [0x04 LL credential]
421     * </pre>
422     * 
423     * @param buffer The buffer where to put the PDU
424     * @return The PDU.
425     */
426    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
427    {
428        try
429        {
430            // The BindRequest Tag
431            buffer.put( LdapConstants.BIND_REQUEST_TAG );
432            buffer.put( TLV.getBytes( getBindRequestLength() ) );
433
434        }
435        catch ( BufferOverflowException boe )
436        {
437            throw new EncoderException( I18n.err( I18n.ERR_04005 ) );
438        }
439
440        // The version (LDAP V3 only)
441        BerValue.encode( buffer, 3 );
442
443        Dn dn = getDn();
444
445        if ( !Dn.isNullOrEmpty( dn ) )
446        {
447            // A DN has been provided
448            BerValue.encode( buffer, dnBytes );
449        }
450        else
451        {
452            // No DN has been provided, let's use the name as a string instead
453            BerValue.encode( buffer, nameBytes );
454        }
455
456        byte[] credentials = getCredentials();
457
458        // The authentication
459        if ( isSimple() )
460        {
461            // Simple authentication
462            try
463            {
464                // The simpleAuthentication Tag
465                buffer.put( ( byte ) LdapConstants.BIND_REQUEST_SIMPLE_TAG );
466
467                if ( credentials != null )
468                {
469                    buffer.put( TLV.getBytes( credentials.length ) );
470
471                    if ( credentials.length != 0 )
472                    {
473                        buffer.put( credentials );
474                    }
475                }
476                else
477                {
478                    buffer.put( ( byte ) 0 );
479                }
480            }
481            catch ( BufferOverflowException boe )
482            {
483                String msg = I18n.err( I18n.ERR_04005 );
484                throw new EncoderException( msg );
485            }
486        }
487        else
488        {
489            // SASL Bind
490            try
491            {
492                // The saslAuthentication Tag
493                buffer.put( ( byte ) LdapConstants.BIND_REQUEST_SASL_TAG );
494
495                buffer.put( TLV
496                    .getBytes( saslMechanismLength + saslCredentialsLength ) );
497
498                BerValue.encode( buffer, mechanismBytes );
499
500                if ( credentials != null )
501                {
502                    BerValue.encode( buffer, credentials );
503                }
504            }
505            catch ( BufferOverflowException boe )
506            {
507                String msg = I18n.err( I18n.ERR_04005 );
508                throw new EncoderException( msg );
509            }
510        }
511
512        return buffer;
513    }
514}