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