001/* 002 * Copyright 2009-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2017 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.protocol; 022 023 024 025import com.unboundid.asn1.ASN1Buffer; 026import com.unboundid.asn1.ASN1BufferSequence; 027import com.unboundid.asn1.ASN1Element; 028import com.unboundid.asn1.ASN1Integer; 029import com.unboundid.asn1.ASN1OctetString; 030import com.unboundid.asn1.ASN1Sequence; 031import com.unboundid.asn1.ASN1StreamReader; 032import com.unboundid.asn1.ASN1StreamReaderSequence; 033import com.unboundid.ldap.sdk.BindRequest; 034import com.unboundid.ldap.sdk.Control; 035import com.unboundid.ldap.sdk.GenericSASLBindRequest; 036import com.unboundid.ldap.sdk.LDAPException; 037import com.unboundid.ldap.sdk.ResultCode; 038import com.unboundid.ldap.sdk.SimpleBindRequest; 039import com.unboundid.util.LDAPSDKUsageException; 040import com.unboundid.util.NotMutable; 041import com.unboundid.util.InternalUseOnly; 042import com.unboundid.util.ThreadSafety; 043import com.unboundid.util.ThreadSafetyLevel; 044 045import static com.unboundid.ldap.protocol.ProtocolMessages.*; 046import static com.unboundid.util.Debug.*; 047import static com.unboundid.util.StaticUtils.*; 048import static com.unboundid.util.Validator.*; 049 050 051 052/** 053 * This class provides an implementation of an LDAP bind request protocol op. 054 */ 055@InternalUseOnly() 056@NotMutable() 057@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 058public final class BindRequestProtocolOp 059 implements ProtocolOp 060{ 061 /** 062 * The credentials type for simple bind requests. 063 */ 064 public static final byte CRED_TYPE_SIMPLE = (byte) 0x80; 065 066 067 068 /** 069 * The credentials type for SASL bind requests. 070 */ 071 public static final byte CRED_TYPE_SASL = (byte) 0xA3; 072 073 074 075 /** 076 * The serial version UID for this serializable class. 077 */ 078 private static final long serialVersionUID = 6661208657485444954L; 079 080 081 082 // The credentials to use for SASL authentication. 083 private final ASN1OctetString saslCredentials; 084 085 // The password to use for simple authentication. 086 private final ASN1OctetString simplePassword; 087 088 // The credentials type for this bind request. 089 private final byte credentialsType; 090 091 // The protocol version for this bind request. 092 private final int version; 093 094 // The bind DN to use for this bind request. 095 private final String bindDN; 096 097 // The name of the SASL mechanism. 098 private final String saslMechanism; 099 100 101 102 /** 103 * Creates a new bind request protocol op for a simple bind. 104 * 105 * @param bindDN The DN for this bind request. 106 * @param password The password for this bind request. 107 */ 108 public BindRequestProtocolOp(final String bindDN, final String password) 109 { 110 if (bindDN == null) 111 { 112 this.bindDN = ""; 113 } 114 else 115 { 116 this.bindDN = bindDN; 117 } 118 119 if (password == null) 120 { 121 simplePassword = new ASN1OctetString(CRED_TYPE_SIMPLE); 122 } 123 else 124 { 125 simplePassword = new ASN1OctetString(CRED_TYPE_SIMPLE, password); 126 } 127 128 version = 3; 129 credentialsType = CRED_TYPE_SIMPLE; 130 saslMechanism = null; 131 saslCredentials = null; 132 } 133 134 135 136 /** 137 * Creates a new bind request protocol op for a simple bind. 138 * 139 * @param bindDN The DN for this bind request. 140 * @param password The password for this bind request. 141 */ 142 public BindRequestProtocolOp(final String bindDN, final byte[] password) 143 { 144 if (bindDN == null) 145 { 146 this.bindDN = ""; 147 } 148 else 149 { 150 this.bindDN = bindDN; 151 } 152 153 if (password == null) 154 { 155 simplePassword = new ASN1OctetString(CRED_TYPE_SIMPLE); 156 } 157 else 158 { 159 simplePassword = new ASN1OctetString(CRED_TYPE_SIMPLE, password); 160 } 161 162 version = 3; 163 credentialsType = CRED_TYPE_SIMPLE; 164 saslMechanism = null; 165 saslCredentials = null; 166 } 167 168 169 170 /** 171 * Creates a new bind request protocol op for a SASL bind. 172 * 173 * @param bindDN The DN for this bind request. 174 * @param saslMechanism The name of the SASL mechanism for this bind 175 * request. It must not be {@code null}. 176 * @param saslCredentials The SASL credentials for this bind request, if 177 * any. 178 */ 179 public BindRequestProtocolOp(final String bindDN, final String saslMechanism, 180 final ASN1OctetString saslCredentials) 181 { 182 this.saslMechanism = saslMechanism; 183 this.saslCredentials = saslCredentials; 184 185 if (bindDN == null) 186 { 187 this.bindDN = ""; 188 } 189 else 190 { 191 this.bindDN = bindDN; 192 } 193 194 version = 3; 195 credentialsType = CRED_TYPE_SASL; 196 simplePassword = null; 197 } 198 199 200 201 /** 202 * Creates a new bind request protocol op from the provided bind request 203 * object. 204 * 205 * @param request The simple bind request to use to create this protocol op. 206 * It must have been created with a static password rather 207 * than using a password provider. 208 * 209 * @throws LDAPSDKUsageException If the provided simple bind request is 210 * configured to use a password provider 211 * rather than a static password. 212 */ 213 public BindRequestProtocolOp(final SimpleBindRequest request) 214 throws LDAPSDKUsageException 215 { 216 version = 3; 217 credentialsType = CRED_TYPE_SIMPLE; 218 bindDN = request.getBindDN(); 219 simplePassword = request.getPassword(); 220 saslMechanism = null; 221 saslCredentials = null; 222 223 if (simplePassword == null) 224 { 225 throw new LDAPSDKUsageException( 226 ERR_BIND_REQUEST_CANNOT_CREATE_WITH_PASSWORD_PROVIDER.get()); 227 } 228 } 229 230 231 232 /** 233 * Creates a new bind request protocol op from the provided bind request 234 * object. 235 * 236 * @param request The generic SASL bind request to use to create this 237 * protocol op. 238 */ 239 public BindRequestProtocolOp(final GenericSASLBindRequest request) 240 { 241 version = 3; 242 credentialsType = CRED_TYPE_SASL; 243 bindDN = request.getBindDN(); 244 simplePassword = null; 245 saslMechanism = request.getSASLMechanismName(); 246 saslCredentials = request.getCredentials(); 247 } 248 249 250 251 /** 252 * Creates a new bind request protocol op read from the provided ASN.1 stream 253 * reader. 254 * 255 * @param reader The ASN.1 stream reader from which to read the bind request 256 * protocol op. 257 * 258 * @throws LDAPException If a problem occurs while reading or parsing the 259 * bind request. 260 */ 261 BindRequestProtocolOp(final ASN1StreamReader reader) 262 throws LDAPException 263 { 264 try 265 { 266 reader.beginSequence(); 267 version = reader.readInteger(); 268 bindDN = reader.readString(); 269 credentialsType = (byte) reader.peek(); 270 271 ensureNotNull(bindDN); 272 273 switch (credentialsType) 274 { 275 case CRED_TYPE_SIMPLE: 276 simplePassword = 277 new ASN1OctetString(credentialsType, reader.readBytes()); 278 saslMechanism = null; 279 saslCredentials = null; 280 ensureNotNull(bindDN); 281 break; 282 283 case CRED_TYPE_SASL: 284 final ASN1StreamReaderSequence saslSequence = reader.beginSequence(); 285 saslMechanism = reader.readString(); 286 ensureNotNull(saslMechanism); 287 if (saslSequence.hasMoreElements()) 288 { 289 saslCredentials = new ASN1OctetString(reader.readBytes()); 290 } 291 else 292 { 293 saslCredentials = null; 294 } 295 simplePassword = null; 296 break; 297 298 default: 299 throw new LDAPException(ResultCode.DECODING_ERROR, 300 ERR_BIND_REQUEST_INVALID_CRED_TYPE.get(toHex(credentialsType))); 301 } 302 } 303 catch (LDAPException le) 304 { 305 debugException(le); 306 throw le; 307 } 308 catch (Exception e) 309 { 310 debugException(e); 311 312 throw new LDAPException(ResultCode.DECODING_ERROR, 313 ERR_BIND_REQUEST_CANNOT_DECODE.get(getExceptionMessage(e)), e); 314 } 315 } 316 317 318 319 /** 320 * Creates a new bind request protocol op with the provided information. 321 * 322 * @param version The protocol version. 323 * @param bindDN The bind DN. It must not be {@code null} (but may 324 * be empty). 325 * @param credentialsType The type of credentials supplied. 326 * @param simplePassword The password for simple authentication, if 327 * appropriate. 328 * @param saslMechanism The name of the SASL mechanism, if appropriate. 329 * @param saslCredentials The SASL credentials, if appropriate. 330 */ 331 private BindRequestProtocolOp(final int version, final String bindDN, 332 final byte credentialsType, 333 final ASN1OctetString simplePassword, 334 final String saslMechanism, 335 final ASN1OctetString saslCredentials) 336 { 337 this.version = version; 338 this.bindDN = bindDN; 339 this.credentialsType = credentialsType; 340 this.simplePassword = simplePassword; 341 this.saslMechanism = saslMechanism; 342 this.saslCredentials = saslCredentials; 343 } 344 345 346 347 /** 348 * Retrieves the protocol version for this bind request. 349 * 350 * @return The protocol version for this bind request. 351 */ 352 public int getVersion() 353 { 354 return version; 355 } 356 357 358 359 /** 360 * Retrieves the bind DN for this bind request. 361 * 362 * @return The bind DN for this bind request, or an empty string if none was 363 * provided. 364 */ 365 public String getBindDN() 366 { 367 return bindDN; 368 } 369 370 371 372 /** 373 * Retrieves the credentials type for this bind request. It will either be 374 * {@link #CRED_TYPE_SIMPLE} or {@link #CRED_TYPE_SASL}. 375 * 376 * @return The credentials type for this bind request. 377 */ 378 public byte getCredentialsType() 379 { 380 return credentialsType; 381 } 382 383 384 385 /** 386 * Retrieves the password to use for simple authentication. 387 * 388 * @return The password to use for simple authentication, or {@code null} if 389 * SASL authentication will be used. 390 */ 391 public ASN1OctetString getSimplePassword() 392 { 393 return simplePassword; 394 } 395 396 397 398 /** 399 * Retrieves the name of the SASL mechanism for this bind request. 400 * 401 * @return The name of the SASL mechanism for this bind request, or 402 * {@code null} if simple authentication will be used. 403 */ 404 public String getSASLMechanism() 405 { 406 return saslMechanism; 407 } 408 409 410 411 /** 412 * Retrieves the credentials to use for SASL authentication, if any. 413 * 414 * @return The credentials to use for SASL authentication, or {@code null} if 415 * there are no SASL credentials or if simple authentication will be 416 * used. 417 */ 418 public ASN1OctetString getSASLCredentials() 419 { 420 return saslCredentials; 421 } 422 423 424 425 /** 426 * {@inheritDoc} 427 */ 428 public byte getProtocolOpType() 429 { 430 return LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST; 431 } 432 433 434 435 /** 436 * {@inheritDoc} 437 */ 438 public ASN1Element encodeProtocolOp() 439 { 440 final ASN1Element credentials; 441 if (credentialsType == CRED_TYPE_SIMPLE) 442 { 443 credentials = simplePassword; 444 } 445 else 446 { 447 if (saslCredentials == null) 448 { 449 credentials = new ASN1Sequence(CRED_TYPE_SASL, 450 new ASN1OctetString(saslMechanism)); 451 } 452 else 453 { 454 credentials = new ASN1Sequence(CRED_TYPE_SASL, 455 new ASN1OctetString(saslMechanism), 456 saslCredentials); 457 } 458 } 459 460 return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST, 461 new ASN1Integer(version), 462 new ASN1OctetString(bindDN), 463 credentials); 464 } 465 466 467 468 /** 469 * Decodes the provided ASN.1 element as a bind request protocol op. 470 * 471 * @param element The ASN.1 element to be decoded. 472 * 473 * @return The decoded bind request protocol op. 474 * 475 * @throws LDAPException If the provided ASN.1 element cannot be decoded as 476 * a bind request protocol op. 477 */ 478 public static BindRequestProtocolOp decodeProtocolOp( 479 final ASN1Element element) 480 throws LDAPException 481 { 482 try 483 { 484 final ASN1Element[] elements = 485 ASN1Sequence.decodeAsSequence(element).elements(); 486 final int version = ASN1Integer.decodeAsInteger(elements[0]).intValue(); 487 final String bindDN = 488 ASN1OctetString.decodeAsOctetString(elements[1]).stringValue(); 489 490 final ASN1OctetString saslCredentials; 491 final ASN1OctetString simplePassword; 492 final String saslMechanism; 493 switch (elements[2].getType()) 494 { 495 case CRED_TYPE_SIMPLE: 496 simplePassword = ASN1OctetString.decodeAsOctetString(elements[2]); 497 saslMechanism = null; 498 saslCredentials = null; 499 break; 500 501 case CRED_TYPE_SASL: 502 final ASN1Element[] saslElements = 503 ASN1Sequence.decodeAsSequence(elements[2]).elements(); 504 saslMechanism = ASN1OctetString.decodeAsOctetString(saslElements[0]). 505 stringValue(); 506 if (saslElements.length == 1) 507 { 508 saslCredentials = null; 509 } 510 else 511 { 512 saslCredentials = 513 ASN1OctetString.decodeAsOctetString(saslElements[1]); 514 } 515 516 simplePassword = null; 517 break; 518 519 default: 520 throw new LDAPException(ResultCode.DECODING_ERROR, 521 ERR_BIND_REQUEST_INVALID_CRED_TYPE.get( 522 toHex(elements[2].getType()))); 523 } 524 525 return new BindRequestProtocolOp(version, bindDN, elements[2].getType(), 526 simplePassword, saslMechanism, saslCredentials); 527 } 528 catch (final LDAPException le) 529 { 530 debugException(le); 531 throw le; 532 } 533 catch (final Exception e) 534 { 535 debugException(e); 536 throw new LDAPException(ResultCode.DECODING_ERROR, 537 ERR_BIND_REQUEST_CANNOT_DECODE.get(getExceptionMessage(e)), 538 e); 539 } 540 } 541 542 543 544 /** 545 * {@inheritDoc} 546 */ 547 public void writeTo(final ASN1Buffer buffer) 548 { 549 final ASN1BufferSequence opSequence = 550 buffer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST); 551 buffer.addInteger(version); 552 buffer.addOctetString(bindDN); 553 554 if (credentialsType == CRED_TYPE_SIMPLE) 555 { 556 buffer.addElement(simplePassword); 557 } 558 else 559 { 560 final ASN1BufferSequence saslSequence = 561 buffer.beginSequence(CRED_TYPE_SASL); 562 buffer.addOctetString(saslMechanism); 563 if (saslCredentials != null) 564 { 565 buffer.addElement(saslCredentials); 566 } 567 saslSequence.end(); 568 } 569 opSequence.end(); 570 buffer.setZeroBufferOnClear(); 571 } 572 573 574 575 /** 576 * Creates a new bind request object from this bind request protocol op. 577 * 578 * @param controls The set of controls to include in the bind request. It 579 * may be empty or {@code null} if no controls should be 580 * included. 581 * 582 * @return The bind request that was created. 583 */ 584 public BindRequest toBindRequest(final Control... controls) 585 { 586 if (credentialsType == CRED_TYPE_SIMPLE) 587 { 588 return new SimpleBindRequest(bindDN, simplePassword.getValue(), 589 controls); 590 } 591 else 592 { 593 return new GenericSASLBindRequest(bindDN, saslMechanism, 594 saslCredentials, controls); 595 } 596 } 597 598 599 600 /** 601 * Retrieves a string representation of this protocol op. 602 * 603 * @return A string representation of this protocol op. 604 */ 605 @Override() 606 public String toString() 607 { 608 final StringBuilder buffer = new StringBuilder(); 609 toString(buffer); 610 return buffer.toString(); 611 } 612 613 614 615 /** 616 * {@inheritDoc} 617 */ 618 public void toString(final StringBuilder buffer) 619 { 620 buffer.append("BindRequestProtocolOp(version="); 621 buffer.append(version); 622 buffer.append(", bindDN='"); 623 buffer.append(bindDN); 624 buffer.append("', type="); 625 626 if (credentialsType == CRED_TYPE_SIMPLE) 627 { 628 buffer.append("simple"); 629 } 630 else 631 { 632 buffer.append("SASL, mechanism="); 633 buffer.append(saslMechanism); 634 } 635 636 buffer.append(')'); 637 } 638}