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.api.ldap.model.message; 021 022 023import java.util.Arrays; 024 025import org.apache.directory.api.i18n.I18n; 026import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; 027import org.apache.directory.api.ldap.model.name.Dn; 028import org.apache.directory.api.util.Strings; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032 033/** 034 * Bind protocol operation request which authenticates and begins a client 035 * session. Does not yet contain interfaces for SASL authentication mechanisms. 036 * 037 * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a> 038 */ 039public class BindRequestImpl extends AbstractAbandonableRequest implements BindRequest 040{ 041 042 /** A logger */ 043 private static final Logger LOG = LoggerFactory.getLogger( BindRequestImpl.class ); 044 045 /** 046 * Distinguished name identifying the name of the authenticating subject - 047 * defaults to the empty string 048 */ 049 private Dn dn; 050 051 /** 052 * String identifying the name of the authenticating subject - 053 * defaults to the empty string 054 */ 055 private String name; 056 057 /** The passwords, keys or tickets used to verify user identity */ 058 private byte[] credentials; 059 060 /** A storage for credentials hashCode */ 061 private int hCredentials; 062 063 /** The mechanism used to decode user identity */ 064 private String mechanism; 065 066 /** Simple vs. SASL authentication mode flag */ 067 private boolean isSimple = true; 068 069 /** Bind behavior exhibited by protocol version */ 070 private boolean isVersion3 = true; 071 072 /** The associated response */ 073 public BindResponse response; 074 075 076 // ------------------------------------------------------------------------ 077 // Constructors 078 // ------------------------------------------------------------------------ 079 /** 080 * Creates an BindRequest implementation to bind to an LDAP server. 081 */ 082 public BindRequestImpl() 083 { 084 super( -1, MessageTypeEnum.BIND_REQUEST ); 085 hCredentials = 0; 086 } 087 088 089 // ----------------------------------------------------------------------- 090 // BindRequest Interface Method Implementations 091 // ----------------------------------------------------------------------- 092 093 /** 094 * {@inheritDoc} 095 */ 096 public boolean isSimple() 097 { 098 return isSimple; 099 } 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}