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.shared.ldap.codec.bind;
021    
022    
023    import java.nio.BufferOverflowException;
024    import java.nio.ByteBuffer;
025    
026    import org.apache.directory.shared.asn1.ber.tlv.TLV;
027    import org.apache.directory.shared.asn1.ber.tlv.Value;
028    import org.apache.directory.shared.asn1.codec.EncoderException;
029    import org.apache.directory.shared.ldap.codec.LdapConstants;
030    import org.apache.directory.shared.ldap.codec.LdapMessageCodec;
031    import org.apache.directory.shared.ldap.name.LdapDN;
032    import org.apache.directory.shared.ldap.util.StringTools;
033    
034    
035    /**
036     * A BindRequest ldapObject. It's a sub-class of Asn1Object, and it extends the
037     * Asn1Object class to be seen as a member of the LdapMessage CHOICE.
038     * 
039     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
040     * @version $Rev: 764131 $, $Date: 2009-04-11 03:03:00 +0200 (Sam, 11 avr 2009) $, 
041     */
042    public class BindRequestCodec extends LdapMessageCodec
043    {
044        // ~ Instance fields
045        // ----------------------------------------------------------------------------
046    
047        /** The protocol Version to use. Should be 3 */
048        private int version;
049    
050        /** The name of the user requesting a bind */
051        private LdapDN name;
052    
053        /** The authentication used to bind the user */
054        private LdapAuthentication authentication;
055    
056        /** The bind request length */
057        private int bindRequestLength;
058    
059        /**
060         * Creates a new BindRequest object.
061         */
062        public BindRequestCodec()
063        {
064            super();
065        }
066    
067        /**
068         * Get the message type
069         * 
070         * @return Returns the type.
071         */
072        public int getMessageType()
073        {
074            return LdapConstants.BIND_REQUEST;
075        }
076    
077    
078        /**
079         * Get the user authentication
080         * 
081         * @return The user authentication
082         */
083        public LdapAuthentication getAuthentication()
084        {
085            return authentication;
086        }
087    
088    
089        /**
090         * Get the user simple authentication
091         * 
092         * @return The simple user authentication
093         */
094        public SimpleAuthentication getSimpleAuthentication()
095        {
096            return ( SimpleAuthentication ) authentication;
097        }
098    
099    
100        /**
101         * Get the user sasl authentication
102         * 
103         * @return The sasl user authentication
104         */
105        public SaslCredentials getSaslAuthentication()
106        {
107            return ( SaslCredentials ) authentication;
108        }
109    
110    
111        /**
112         * Set the user authentication
113         * 
114         * @param authentication The user authentication
115         */
116        public void setAuthentication( LdapAuthentication authentication )
117        {
118            this.authentication = authentication;
119        }
120    
121    
122        /**
123         * Get the user name
124         * 
125         * @return The user name
126         */
127        public LdapDN getName()
128        {
129            return name;
130        }
131    
132    
133        /**
134         * Set the user name
135         * 
136         * @param name The user name
137         */
138        public void setName( LdapDN name )
139        {
140            this.name = name;
141        }
142    
143    
144        /**
145         * Get the protocol version
146         * 
147         * @return The protocol version
148         */
149        public int getVersion()
150        {
151            return version;
152        }
153    
154    
155        /**
156         * Check if the Ldap version in use is 3
157         * 
158         * @return true if the ldap version is 3
159         */
160        public boolean isLdapV3()
161        {
162            return version == 3;
163        }
164    
165    
166        /**
167         * Set the protocol version
168         * 
169         * @param version The protocol version
170         */
171        public void setVersion( int version )
172        {
173            this.version = version;
174        }
175    
176    
177        /**
178         * Compute the BindRequest length 
179         * 
180         * BindRequest : 
181         * 0x60 L1 
182         *   | 
183         *   +--> 0x02 0x01 (1..127) version 
184         *   +--> 0x04 L2 name 
185         *   +--> authentication 
186         *   
187         * L2 = Length(name)
188         * L3/4 = Length(authentication) 
189         * Length(BindRequest) = Length(0x60) + Length(L1) + L1 + Length(0x02) + 1 + 1 + 
190         *      Length(0x04) + Length(L2) + L2 + Length(authentication)
191         */
192        public int computeLength()
193        {
194            bindRequestLength = 1 + 1 + 1; // Initialized with version
195    
196            // The name
197            bindRequestLength += 1 + TLV.getNbBytes( LdapDN.getNbBytes( name ) ) + LdapDN.getNbBytes( name );
198    
199            // The authentication
200            bindRequestLength += authentication.computeLength();
201    
202            // Return the result.
203            return 1 + TLV.getNbBytes( bindRequestLength ) + bindRequestLength;
204        }
205    
206    
207        /**
208         * Encode the BindRequest message to a PDU. 
209         * 
210         * BindRequest : 
211         * 
212         * 0x60 LL 
213         *   0x02 LL version         0x80 LL simple 
214         *   0x04 LL name           /   
215         *   authentication.encode() 
216         *                          \ 0x83 LL mechanism [0x04 LL credential]
217         * 
218         * 
219         * @param buffer The buffer where to put the PDU
220         * @return The PDU.
221         */
222        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
223        {
224            if ( buffer == null )
225            {
226                throw new EncoderException( "Cannot put a PDU in a null buffer !" );
227            }
228    
229            try
230            {
231                // The BindRequest Tag
232                buffer.put( LdapConstants.BIND_REQUEST_TAG );
233                buffer.put( TLV.getBytes( bindRequestLength ) );
234    
235            }
236            catch ( BufferOverflowException boe )
237            {
238                throw new EncoderException( "The PDU buffer size is too small !" );
239            }
240    
241            // The version
242            Value.encode( buffer, version );
243    
244            // The name
245            Value.encode( buffer, LdapDN.getBytes( name ) );
246    
247            // The authentication
248            authentication.encode( buffer );
249    
250            return buffer;
251        }
252    
253    
254        /**
255         * Get a String representation of a BindRequest
256         * 
257         * @return A BindRequest String
258         */
259        public String toString()
260        {
261            StringBuffer sb = new StringBuffer();
262    
263            sb.append( "    BindRequest\n" );
264            sb.append( "        Version : '" ).append( version ).append( "'\n" );
265    
266            if ( ( null == name ) || StringTools.isEmpty( name.toString() ) )
267            {
268                sb.append( "        Name : anonymous\n" );
269            }
270            else
271            {
272                sb.append( "        Name : '" ).append( name ).append( "'\n" );
273    
274                if ( authentication instanceof SimpleAuthentication )
275                {
276                    sb.append( "        Simple authentication : '" ).append( authentication ).append( "'\n" );
277                }
278                else
279                {
280                    sb.append( authentication );
281                }
282            }
283    
284            return sb.toString();
285        }
286    
287        /* Used only for test perfs
288        public static void main( String[] args ) throws Exception
289        {
290            Asn1Decoder ldapDecoder = new LdapDecoder();
291    
292            ByteBuffer stream = ByteBuffer.allocate( 0x52 );
293            stream.put( new byte[]
294                 { 
295                 0x30, 0x50,                 // LDAPMessage ::=SEQUENCE {
296                   0x02, 0x01, 0x01,         // messageID MessageID
297                   0x60, 0x2E,               // CHOICE { ..., bindRequest BindRequest, ...
298                                             // BindRequest ::= APPLICATION[0] SEQUENCE {
299                     0x02, 0x01, 0x03,       // version INTEGER (1..127),
300                     0x04, 0x1F,             // name LDAPDN,
301                     'u', 'i', 'd', '=', 'a', 'k', 'a', 'r', 'a', 's', 'u', 'l', 'u', ',', 'd', 'c', '=', 'e', 'x', 'a',
302                     'm', 'p', 'l', 'e', ',', 'd', 'c', '=', 'c', 'o', 'm', 
303                     ( byte ) 0x80, 0x08,    // authentication AuthenticationChoice
304                                             // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
305                                             // ...
306                       'p', 'a', 's', 's', 'w', 'o', 'r', 'd', 
307                   ( byte ) 0xA0, 0x1B, // A control
308                     0x30, 0x19, 
309                       0x04, 0x17, 
310                         0x32, 0x2E, 0x31, 0x36, 0x2E, 0x38, 0x34, 0x30, 0x2E, 0x31, 0x2E, 0x31, 0x31, 0x33, 0x37, 0x33, 
311                         0x30, 0x2E, 0x33, 0x2E, 0x34, 0x2E, 0x32 
312                 } );
313    
314            stream.flip();
315    
316            // Allocate a LdapMessage Container
317            IAsn1Container ldapMessageContainer = new LdapMessageContainer();
318    
319            // Decode the BindRequest PDU
320            try
321            {
322                long t0 = System.currentTimeMillis();
323                for ( int i = 0; i < 10000000; i++ )
324                {
325                    ldapDecoder.decode( stream, ldapMessageContainer );
326                    ( ( LdapMessageContainer ) ldapMessageContainer).clean();
327                    stream.flip();
328                }
329                long t1 = System.currentTimeMillis();
330                System.out.println( "Delta = " + ( t1 - t0 ) );
331                
332                ldapDecoder.decode( stream, ldapMessageContainer );
333            }
334            catch ( DecoderException de )
335            {
336                de.printStackTrace();
337            }
338            catch ( NamingException ne )
339            {
340                ne.printStackTrace();
341            }
342        }
343        */
344    }