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