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 }