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