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