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