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.model.message;
021
022
023import java.util.Arrays;
024
025import org.apache.directory.shared.i18n.I18n;
026import org.apache.directory.shared.ldap.model.exception.MessageException;
027import org.apache.directory.shared.ldap.model.name.Dn;
028import org.apache.directory.shared.util.Strings;
029
030
031/**
032 * Bind protocol operation request which authenticates and begins a client
033 * session. Does not yet contain interfaces for SASL authentication mechanisms.
034 * 
035 * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
036 */
037public class BindRequestImpl extends AbstractAbandonableRequest implements BindRequest
038{
039    /**
040     * Distinguished name identifying the name of the authenticating subject -
041     * defaults to the empty string
042     */
043    private Dn name;
044
045    /** The passwords, keys or tickets used to verify user identity */
046    private byte[] credentials;
047
048    /** A storage for credentials hashCode */
049    private int hCredentials;
050
051    /** The mechanism used to decode user identity */
052    private String mechanism;
053
054    /** Simple vs. SASL authentication mode flag */
055    private boolean isSimple = true;
056
057    /** Bind behavior exhibited by protocol version */
058    private boolean isVersion3 = true;
059
060    /** The associated response */
061    public BindResponse response;
062
063
064    // ------------------------------------------------------------------------
065    // Constructors
066    // ------------------------------------------------------------------------
067    /**
068     * Creates an BindRequest implementation to bind to an LDAP server.
069     */
070    public BindRequestImpl()
071    {
072        super( -1, TYPE );
073        hCredentials = 0;
074    }
075
076
077    // -----------------------------------------------------------------------
078    // BindRequest Interface Method Implementations
079    // -----------------------------------------------------------------------
080
081    /**
082     * {@inheritDoc}
083     */
084    public boolean isSimple()
085    {
086        return isSimple;
087    }
088
089
090    /**
091     * {@inheritDoc}
092     */
093    public boolean getSimple()
094    {
095        return isSimple;
096    }
097
098
099    /**
100     * {@inheritDoc}
101     */
102    public BindRequest setSimple( boolean simple )
103    {
104        this.isSimple = simple;
105        
106        return this;
107    }
108
109
110    /**
111     * {@inheritDoc}
112     */
113    public byte[] getCredentials()
114    {
115        return credentials;
116    }
117
118
119    /**
120     * {@inheritDoc}
121     */
122    public BindRequest setCredentials( String credentials )
123    {
124        return setCredentials( Strings.getBytesUtf8(credentials) );
125    }
126
127
128    /**
129     * {@inheritDoc}
130     */
131    public BindRequest setCredentials( byte[] credentials )
132    {
133        if ( credentials != null )
134        {
135            this.credentials = new byte[credentials.length];
136            System.arraycopy( credentials, 0, this.credentials, 0, credentials.length );
137        }
138        else
139        {
140            this.credentials = null;
141        }
142
143        // Compute the hashcode
144        if ( credentials != null )
145        {
146            hCredentials = 0;
147
148            for ( byte b : credentials )
149            {
150                hCredentials = hCredentials * 31 + b;
151            }
152        }
153        else
154        {
155            hCredentials = 0;
156        }
157        
158        return this;
159    }
160
161
162    /**
163     * {@inheritDoc}
164     */
165    public String getSaslMechanism()
166    {
167        return mechanism;
168    }
169
170
171    /**
172     * {@inheritDoc}
173     */
174    public BindRequest setSaslMechanism( String saslMechanism )
175    {
176        this.isSimple = false;
177        this.mechanism = saslMechanism;
178        
179        return this;
180    }
181
182
183    /**
184     * {@inheritDoc}
185     */
186    public Dn getName()
187    {
188        return name;
189    }
190
191
192    /**
193     * {@inheritDoc}
194     */
195    public BindRequest setName( Dn name )
196    {
197        this.name = name;
198        
199        return this;
200    }
201
202
203    /**
204     * {@inheritDoc}
205     */
206    public boolean isVersion3()
207    {
208        return isVersion3;
209    }
210
211
212    /**
213     * {@inheritDoc}
214     */
215    public boolean getVersion3()
216    {
217        return isVersion3;
218    }
219
220
221    /**
222     * {@inheritDoc}
223     */
224    public BindRequest setVersion3( boolean version3 )
225    {
226        this.isVersion3 = version3;
227        
228        return this;
229    }
230    
231    
232    /**
233     * {@inheritDoc}
234     */
235    public BindRequest setMessageId( int messageId )
236    {
237        super.setMessageId( messageId );
238        
239        return this;
240    }
241
242    
243    /**
244     * {@inheritDoc}
245     */
246    public BindRequest addControl( Control control ) throws MessageException
247    {
248        return (BindRequest)super.addControl( control );
249    }
250    
251    
252    /**
253     * {@inheritDoc}
254     */
255    public BindRequest addAllControls( Control[] controls ) throws MessageException
256    {
257        return (BindRequest)super.addAllControls( controls );
258    }
259    
260    
261    /**
262     * {@inheritDoc}
263     */
264    public BindRequest removeControl( Control control ) throws MessageException
265    {
266        return (BindRequest)super.removeControl( control );
267    }
268
269
270    // -----------------------------------------------------------------------
271    // BindRequest Interface Method Implementations
272    // -----------------------------------------------------------------------
273    /**
274     * Gets the protocol response message type for this request which produces
275     * at least one response.
276     * 
277     * @return the message type of the response.
278     */
279    public MessageTypeEnum getResponseType()
280    {
281        return RESP_TYPE;
282    }
283
284
285    /**
286     * The result containing response for this request.
287     * 
288     * @return the result containing response for this request
289     */
290    public BindResponse getResultResponse()
291    {
292        if ( response == null )
293        {
294            response = new BindResponseImpl( getMessageId() );
295        }
296
297        return response;
298    }
299
300
301    /**
302     * RFC 2251/4511 [Section 4.11]: Abandon, Bind, Unbind, and StartTLS operations
303     * cannot be abandoned.
304     */
305    public void abandon()
306    {
307        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04185 ) );
308    }
309
310
311    /**
312     * {@inheritDoc}
313     */
314    @Override
315    public boolean equals( Object obj )
316    {
317        if ( obj == this )
318        {
319            return true;
320        }
321
322        if ( ( obj == null ) || !( obj instanceof BindRequest) )
323        {
324            return false;
325        }
326
327        if ( !super.equals( obj ) )
328        {
329            return false;
330        }
331
332        BindRequest req = ( BindRequest ) obj;
333
334        if ( req.isSimple() != isSimple() )
335        {
336            return false;
337        }
338
339        if ( req.isVersion3() != isVersion3() )
340        {
341            return false;
342        }
343
344        Dn dn1 = req.getName();
345        Dn dn2 = getName();
346
347        if ( Dn.isNullOrEmpty( dn1) )
348        {
349            if ( !Dn.isNullOrEmpty( dn2 ) )
350            {
351                return false;
352            }
353        }
354        else
355        {
356            if ( Dn.isNullOrEmpty( dn2 ) )
357            {
358                return false;
359            }
360            else if ( !dn1.equals( dn2 ) )
361            {
362                return false;
363            }
364        }
365
366        return Arrays.equals( req.getCredentials(), getCredentials() );
367    }
368
369
370    /**
371     * {@inheritDoc}
372     */
373    @Override
374    public int hashCode()
375    {
376        int hash = 37;
377        hash = hash * 17 + ( credentials == null ? 0 : hCredentials );
378        hash = hash * 17 + ( isSimple ? 0 : 1 );
379        hash = hash * 17 + ( isVersion3 ? 0 : 1 );
380        hash = hash * 17 + ( mechanism == null ? 0 : mechanism.hashCode() );
381        hash = hash * 17 + ( name == null ? 0 : name.hashCode() );
382        hash = hash * 17 + ( response == null ? 0 : response.hashCode() );
383        hash = hash * 17 + super.hashCode();
384
385        return hash;
386    }
387
388
389    /**
390     * Get a String representation of a BindRequest
391     * 
392     * @return A BindRequest String
393     */
394    public String toString()
395    {
396        StringBuffer sb = new StringBuffer();
397        
398        sb.append( "    BindRequest\n" );
399        sb.append( "        Version : '" ).append( isVersion3 ? "3" : "2" ).append( "'\n" );
400
401        if ( ( (name == null ) || Strings.isEmpty(name.getNormName() ) ) && isSimple )
402        {
403            sb.append( "        Name : anonymous\n" );
404        }
405        else
406        {
407            sb.append( "        Name : '" ).append( name.toString() ).append( "'\n" );
408
409            if ( isSimple )
410            {
411                sb.append( "        Simple authentication : '" ).append( Strings.utf8ToString(credentials) )
412                    .append( '/' ).append( Strings.dumpBytes(credentials) ).append( "'\n" );
413            }
414            else
415            {
416                sb.append( "        Sasl credentials\n" );
417                sb.append( "            Mechanism :'" ).append( mechanism ).append( "'\n" );
418
419                if ( credentials == null )
420                {
421                    sb.append( "            Credentials : null" );
422                }
423                else
424                {
425                    sb.append( "            Credentials : (omitted-for-safety)" );
426                }
427            }
428        }
429
430        // The controls if any
431        return super.toString( sb.toString() );
432    }
433}