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      private 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      @Override
97      public boolean isSimple()
98      {
99          return isSimple;
100     }
101 
102 
103     /**
104      * {@inheritDoc}
105      */
106     @Override
107     public boolean getSimple()
108     {
109         return isSimple;
110     }
111 
112 
113     /**
114      * {@inheritDoc}
115      */
116     @Override
117     public BindRequest setSimple( boolean simple )
118     {
119         this.isSimple = simple;
120 
121         return this;
122     }
123 
124 
125     /**
126      * {@inheritDoc}
127      */
128     @Override
129     public byte[] getCredentials()
130     {
131         return credentials;
132     }
133 
134 
135     /**
136      * {@inheritDoc}
137      */
138     @Override
139     public BindRequest setCredentials( String credentials )
140     {
141         return setCredentials( Strings.getBytesUtf8( credentials ) );
142     }
143 
144 
145     /**
146      * {@inheritDoc}
147      */
148     @Override
149     public BindRequest setCredentials( byte[] credentials )
150     {
151         if ( credentials != null )
152         {
153             this.credentials = new byte[credentials.length];
154             System.arraycopy( credentials, 0, this.credentials, 0, credentials.length );
155         }
156         else
157         {
158             this.credentials = null;
159         }
160 
161         // Compute the hashcode
162         if ( credentials != null )
163         {
164             hCredentials = 0;
165 
166             for ( byte b : credentials )
167             {
168                 hCredentials = hCredentials * 31 + b;
169             }
170         }
171         else
172         {
173             hCredentials = 0;
174         }
175 
176         return this;
177     }
178 
179 
180     /**
181      * {@inheritDoc}
182      */
183     @Override
184     public String getSaslMechanism()
185     {
186         return mechanism;
187     }
188 
189 
190     /**
191      * {@inheritDoc}
192      */
193     @Override
194     public BindRequest setSaslMechanism( String saslMechanism )
195     {
196         this.isSimple = false;
197         this.mechanism = saslMechanism;
198 
199         return this;
200     }
201 
202 
203     /**
204      * {@inheritDoc}
205      */
206     @Override
207     public String getName()
208     {
209         return name;
210     }
211 
212 
213     /**
214      * {@inheritDoc}
215      */
216     @Override
217     public BindRequest setName( String name )
218     {
219         this.name = name;
220 
221         try
222         {
223             this.dn = new Dn( name );
224         }
225         catch ( LdapInvalidDnException e )
226         {
227             // This might still be a valid DN (Windows AD binding for instance)
228             LOG.debug( "Unable to convert the name to a DN." );
229             this.dn = null;
230         }
231 
232         return this;
233     }
234 
235 
236     /**
237      * {@inheritDoc}
238      */
239     @Override
240     public Dn getDn()
241     {
242         return dn;
243     }
244 
245 
246     /**
247      * {@inheritDoc}
248      */
249     @Override
250     public BindRequest setDn( Dn dn )
251     {
252         this.dn = dn;
253         this.name = dn.getName();
254 
255         return this;
256     }
257 
258 
259     /**
260      * {@inheritDoc}
261      */
262     @Override
263     public boolean isVersion3()
264     {
265         return isVersion3;
266     }
267 
268 
269     /**
270      * {@inheritDoc}
271      */
272     @Override
273     public boolean getVersion3()
274     {
275         return isVersion3;
276     }
277 
278 
279     /**
280      * {@inheritDoc}
281      */
282     @Override
283     public BindRequest setVersion3( boolean version3 )
284     {
285         this.isVersion3 = version3;
286 
287         return this;
288     }
289 
290 
291     /**
292      * {@inheritDoc}
293      */
294     @Override
295     public BindRequest setMessageId( int messageId )
296     {
297         super.setMessageId( messageId );
298 
299         return this;
300     }
301 
302 
303     /**
304      * {@inheritDoc}
305      */
306     @Override
307     public BindRequest addControl( Control control )
308     {
309         return ( BindRequest ) super.addControl( control );
310     }
311 
312 
313     /**
314      * {@inheritDoc}
315      */
316     @Override
317     public BindRequest addAllControls( Control[] controls )
318     {
319         return ( BindRequest ) super.addAllControls( controls );
320     }
321 
322 
323     /**
324      * {@inheritDoc}
325      */
326     @Override
327     public BindRequest removeControl( Control control )
328     {
329         return ( BindRequest ) super.removeControl( control );
330     }
331 
332 
333     // -----------------------------------------------------------------------
334     // BindRequest Interface Method Implementations
335     // -----------------------------------------------------------------------
336     /**
337      * Gets the protocol response message type for this request which produces
338      * at least one response.
339      * 
340      * @return the message type of the response.
341      */
342     @Override
343     public MessageTypeEnum getResponseType()
344     {
345         return MessageTypeEnum.BIND_RESPONSE;
346     }
347 
348 
349     /**
350      * The result containing response for this request.
351      * 
352      * @return the result containing response for this request
353      */
354     @Override
355     public BindResponse getResultResponse()
356     {
357         if ( response == null )
358         {
359             response = new BindResponseImpl( getMessageId() );
360         }
361 
362         return response;
363     }
364 
365 
366     /**
367      * RFC 2251/4511 [Section 4.11]: Abandon, Bind, Unbind, and StartTLS operations
368      * cannot be abandoned.
369      */
370     @Override
371     public void abandon()
372     {
373         throw new UnsupportedOperationException( I18n.err( I18n.ERR_04185 ) );
374     }
375 
376 
377     /**
378      * {@inheritDoc}
379      */
380     @Override
381     public boolean equals( Object obj )
382     {
383         if ( obj == this )
384         {
385             return true;
386         }
387 
388         if ( ( obj == null ) || !( obj instanceof BindRequest ) )
389         {
390             return false;
391         }
392 
393         if ( !super.equals( obj ) )
394         {
395             return false;
396         }
397 
398         BindRequest req = ( BindRequest ) obj;
399 
400         if ( req.isSimple() != isSimple() )
401         {
402             return false;
403         }
404 
405         if ( req.isVersion3() != isVersion3() )
406         {
407             return false;
408         }
409 
410         String name1 = req.getName();
411         String name2 = getName();
412 
413         if ( Strings.isEmpty( name1 ) )
414         {
415             if ( !Strings.isEmpty( name2 ) )
416             {
417                 return false;
418             }
419         }
420         else
421         {
422             if ( Strings.isEmpty( name2 ) )
423             {
424                 return false;
425             }
426             else if ( !name2.equals( name1 ) )
427             {
428                 return false;
429             }
430         }
431 
432         Dn dn1 = req.getDn();
433         Dn dn2 = getDn();
434 
435         if ( Dn.isNullOrEmpty( dn1 ) )
436         {
437             if ( !Dn.isNullOrEmpty( dn2 ) )
438             {
439                 return false;
440             }
441         }
442         else
443         {
444             if ( Dn.isNullOrEmpty( dn2 ) )
445             {
446                 return false;
447             }
448             else if ( !dn1.equals( dn2 ) )
449             {
450                 return false;
451             }
452         }
453 
454         return Arrays.equals( req.getCredentials(), getCredentials() );
455     }
456 
457 
458     /**
459      * {@inheritDoc}
460      */
461     @Override
462     public int hashCode()
463     {
464         int hash = 37;
465         hash = hash * 17 + ( credentials == null ? 0 : hCredentials );
466         hash = hash * 17 + ( isSimple ? 0 : 1 );
467         hash = hash * 17 + ( isVersion3 ? 0 : 1 );
468         hash = hash * 17 + ( mechanism == null ? 0 : mechanism.hashCode() );
469         hash = hash * 17 + ( name == null ? 0 : name.hashCode() );
470         hash = hash * 17 + ( response == null ? 0 : response.hashCode() );
471         hash = hash * 17 + super.hashCode();
472 
473         return hash;
474     }
475 
476 
477     /**
478      * Get a String representation of a BindRequest
479      * 
480      * @return A BindRequest String
481      */
482     @Override
483     public String toString()
484     {
485         StringBuilder sb = new StringBuilder();
486 
487         sb.append( "    BindRequest\n" );
488         sb.append( "        Version : '" ).append( isVersion3 ? "3" : "2" ).append( "'\n" );
489 
490         if ( ( ( Strings.isEmpty( name ) ) || ( dn == null ) || Strings.isEmpty( dn.getNormName() ) )
491             && isSimple )
492         {
493             sb.append( "        Name : anonymous\n" );
494         }
495         else
496         {
497             sb.append( "        Name : '" ).append( name ).append( "'\n" );
498 
499             if ( isSimple )
500             {
501                 sb.append( "        Simple authentication : '" ).append( "(omitted-for-safety)" ).append( "'\n" );
502             }
503             else
504             {
505                 sb.append( "        Sasl credentials\n" );
506                 sb.append( "            Mechanism :'" ).append( mechanism ).append( "'\n" );
507 
508                 if ( credentials == null )
509                 {
510                     sb.append( "            Credentials : null" );
511                 }
512                 else
513                 {
514                     sb.append( "            Credentials : (omitted-for-safety)" );
515                 }
516             }
517         }
518 
519         // The controls if any
520         return super.toString( sb.toString() );
521     }
522 }