View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.api.ldap.model.message;
21  
22  
23  import java.util.Arrays;
24  
25  import org.apache.directory.api.i18n.I18n;
26  import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
27  import org.apache.directory.api.ldap.model.name.Dn;
28  import org.apache.directory.api.util.Strings;
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  
33  /**
34   * Bind protocol operation request which authenticates and begins a client
35   * session. Does not yet contain interfaces for SASL authentication mechanisms.
36   * 
37   * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
38   */
39  public class BindRequestImpl extends AbstractAbandonableRequest implements BindRequest
40  {
41  
42      /** A logger */
43      private static final Logger LOG = LoggerFactory.getLogger( BindRequestImpl.class );
44  
45      /**
46       * Distinguished name identifying the name of the authenticating subject -
47       * defaults to the empty string
48       */
49      private Dn dn;
50  
51      /**
52       * String identifying the name of the authenticating subject -
53       * defaults to the empty string
54       */
55      private String name;
56  
57      /** The passwords, keys or tickets used to verify user identity */
58      private byte[] credentials;
59  
60      /** A storage for credentials hashCode */
61      private int hCredentials;
62  
63      /** The mechanism used to decode user identity */
64      private String mechanism;
65  
66      /** Simple vs. SASL authentication mode flag */
67      private boolean isSimple = true;
68  
69      /** Bind behavior exhibited by protocol version */
70      private boolean isVersion3 = true;
71  
72      /** The associated response */
73      public BindResponse response;
74  
75  
76      // ------------------------------------------------------------------------
77      // Constructors
78      // ------------------------------------------------------------------------
79      /**
80       * Creates an BindRequest implementation to bind to an LDAP server.
81       */
82      public BindRequestImpl()
83      {
84          super( -1, MessageTypeEnum.BIND_REQUEST );
85          hCredentials = 0;
86      }
87  
88  
89      // -----------------------------------------------------------------------
90      // BindRequest Interface Method Implementations
91      // -----------------------------------------------------------------------
92  
93      /**
94       * {@inheritDoc}
95       */
96      public boolean isSimple()
97      {
98          return isSimple;
99      }
100 
101 
102     /**
103      * {@inheritDoc}
104      */
105     public boolean getSimple()
106     {
107         return isSimple;
108     }
109 
110 
111     /**
112      * {@inheritDoc}
113      */
114     public BindRequest setSimple( boolean simple )
115     {
116         this.isSimple = simple;
117 
118         return this;
119     }
120 
121 
122     /**
123      * {@inheritDoc}
124      */
125     public byte[] getCredentials()
126     {
127         return credentials;
128     }
129 
130 
131     /**
132      * {@inheritDoc}
133      */
134     public BindRequest setCredentials( String credentials )
135     {
136         return setCredentials( Strings.getBytesUtf8( credentials ) );
137     }
138 
139 
140     /**
141      * {@inheritDoc}
142      */
143     public BindRequest setCredentials( byte[] credentials )
144     {
145         if ( credentials != null )
146         {
147             this.credentials = new byte[credentials.length];
148             System.arraycopy( credentials, 0, this.credentials, 0, credentials.length );
149         }
150         else
151         {
152             this.credentials = null;
153         }
154 
155         // Compute the hashcode
156         if ( credentials != null )
157         {
158             hCredentials = 0;
159 
160             for ( byte b : credentials )
161             {
162                 hCredentials = hCredentials * 31 + b;
163             }
164         }
165         else
166         {
167             hCredentials = 0;
168         }
169 
170         return this;
171     }
172 
173 
174     /**
175      * {@inheritDoc}
176      */
177     public String getSaslMechanism()
178     {
179         return mechanism;
180     }
181 
182 
183     /**
184      * {@inheritDoc}
185      */
186     public BindRequest setSaslMechanism( String saslMechanism )
187     {
188         this.isSimple = false;
189         this.mechanism = saslMechanism;
190 
191         return this;
192     }
193 
194 
195     /**
196      * {@inheritDoc}
197      */
198     public String getName()
199     {
200         return name;
201     }
202 
203 
204     /**
205      * {@inheritDoc}
206      */
207     public BindRequest setName( String name )
208     {
209         this.name = name;
210 
211         try
212         {
213             this.dn = new Dn( name );
214         }
215         catch ( LdapInvalidDnException e )
216         {
217             // This might still be a valid DN (Windows AD binding for instance)
218             LOG.info( "Unable to convert the name to a DN.", e );
219             this.dn = null;
220         }
221 
222         return this;
223     }
224 
225 
226     /**
227      * {@inheritDoc}
228      */
229     public Dn getDn()
230     {
231         return dn;
232     }
233 
234 
235     /**
236      * {@inheritDoc}
237      */
238     public BindRequest setDn( Dn dn )
239     {
240         this.dn = dn;
241         this.name = dn.getName();
242 
243         return this;
244     }
245 
246 
247     /**
248      * {@inheritDoc}
249      */
250     public boolean isVersion3()
251     {
252         return isVersion3;
253     }
254 
255 
256     /**
257      * {@inheritDoc}
258      */
259     public boolean getVersion3()
260     {
261         return isVersion3;
262     }
263 
264 
265     /**
266      * {@inheritDoc}
267      */
268     public BindRequest setVersion3( boolean version3 )
269     {
270         this.isVersion3 = version3;
271 
272         return this;
273     }
274 
275 
276     /**
277      * {@inheritDoc}
278      */
279     public BindRequest setMessageId( int messageId )
280     {
281         super.setMessageId( messageId );
282 
283         return this;
284     }
285 
286 
287     /**
288      * {@inheritDoc}
289      */
290     public BindRequest addControl( Control control )
291     {
292         return ( BindRequest ) super.addControl( control );
293     }
294 
295 
296     /**
297      * {@inheritDoc}
298      */
299     public BindRequest addAllControls( Control[] controls )
300     {
301         return ( BindRequest ) super.addAllControls( controls );
302     }
303 
304 
305     /**
306      * {@inheritDoc}
307      */
308     public BindRequest removeControl( Control control )
309     {
310         return ( BindRequest ) super.removeControl( control );
311     }
312 
313 
314     // -----------------------------------------------------------------------
315     // BindRequest Interface Method Implementations
316     // -----------------------------------------------------------------------
317     /**
318      * Gets the protocol response message type for this request which produces
319      * at least one response.
320      * 
321      * @return the message type of the response.
322      */
323     public MessageTypeEnum getResponseType()
324     {
325         return MessageTypeEnum.BIND_RESPONSE;
326     }
327 
328 
329     /**
330      * The result containing response for this request.
331      * 
332      * @return the result containing response for this request
333      */
334     public BindResponse getResultResponse()
335     {
336         if ( response == null )
337         {
338             response = new BindResponseImpl( getMessageId() );
339         }
340 
341         return response;
342     }
343 
344 
345     /**
346      * RFC 2251/4511 [Section 4.11]: Abandon, Bind, Unbind, and StartTLS operations
347      * cannot be abandoned.
348      */
349     public void abandon()
350     {
351         throw new UnsupportedOperationException( I18n.err( I18n.ERR_04185 ) );
352     }
353 
354 
355     /**
356      * {@inheritDoc}
357      */
358     @Override
359     public boolean equals( Object obj )
360     {
361         if ( obj == this )
362         {
363             return true;
364         }
365 
366         if ( ( obj == null ) || !( obj instanceof BindRequest ) )
367         {
368             return false;
369         }
370 
371         if ( !super.equals( obj ) )
372         {
373             return false;
374         }
375 
376         BindRequest req = ( BindRequest ) obj;
377 
378         if ( req.isSimple() != isSimple() )
379         {
380             return false;
381         }
382 
383         if ( req.isVersion3() != isVersion3() )
384         {
385             return false;
386         }
387 
388         String name1 = req.getName();
389         String name2 = getName();
390 
391         if ( Strings.isEmpty( name1 ) )
392         {
393             if ( !Strings.isEmpty( name2 ) )
394             {
395                 return false;
396             }
397         }
398         else
399         {
400             if ( Strings.isEmpty( name2 ) )
401             {
402                 return false;
403             }
404             else if ( !name2.equals( name1 ) )
405             {
406                 return false;
407             }
408         }
409 
410         Dn dn1 = req.getDn();
411         Dn dn2 = getDn();
412 
413         if ( Dn.isNullOrEmpty( dn1 ) )
414         {
415             if ( !Dn.isNullOrEmpty( dn2 ) )
416             {
417                 return false;
418             }
419         }
420         else
421         {
422             if ( Dn.isNullOrEmpty( dn2 ) )
423             {
424                 return false;
425             }
426             else if ( !dn1.equals( dn2 ) )
427             {
428                 return false;
429             }
430         }
431 
432         return Arrays.equals( req.getCredentials(), getCredentials() );
433     }
434 
435 
436     /**
437      * {@inheritDoc}
438      */
439     @Override
440     public int hashCode()
441     {
442         int hash = 37;
443         hash = hash * 17 + ( credentials == null ? 0 : hCredentials );
444         hash = hash * 17 + ( isSimple ? 0 : 1 );
445         hash = hash * 17 + ( isVersion3 ? 0 : 1 );
446         hash = hash * 17 + ( mechanism == null ? 0 : mechanism.hashCode() );
447         hash = hash * 17 + ( name == null ? 0 : name.hashCode() );
448         hash = hash * 17 + ( response == null ? 0 : response.hashCode() );
449         hash = hash * 17 + super.hashCode();
450 
451         return hash;
452     }
453 
454 
455     /**
456      * Get a String representation of a BindRequest
457      * 
458      * @return A BindRequest String
459      */
460     public String toString()
461     {
462         StringBuffer sb = new StringBuffer();
463 
464         sb.append( "    BindRequest\n" );
465         sb.append( "        Version : '" ).append( isVersion3 ? "3" : "2" ).append( "'\n" );
466 
467         if ( ( ( Strings.isEmpty( name ) ) || ( dn == null ) || Strings.isEmpty( dn.getNormName() ) )
468             && isSimple )
469         {
470             sb.append( "        Name : anonymous\n" );
471         }
472         else
473         {
474             sb.append( "        Name : '" ).append( name ).append( "'\n" );
475 
476             if ( isSimple )
477             {
478                 sb.append( "        Simple authentication : '" ).append( Strings.utf8ToString( credentials ) )
479                     .append( '/' ).append( Strings.dumpBytes( credentials ) ).append( "'\n" );
480             }
481             else
482             {
483                 sb.append( "        Sasl credentials\n" );
484                 sb.append( "            Mechanism :'" ).append( mechanism ).append( "'\n" );
485 
486                 if ( credentials == null )
487                 {
488                     sb.append( "            Credentials : null" );
489                 }
490                 else
491                 {
492                     sb.append( "            Credentials : (omitted-for-safety)" );
493                 }
494             }
495         }
496 
497         // The controls if any
498         return super.toString( sb.toString() );
499     }
500 }