001/* 002 * Copyright 2009-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2018 Ping Identity Corporation 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 (final LDAPException le) 304 { 305 debugException(le); 306 throw le; 307 } 308 catch (final 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 @Override() 429 public byte getProtocolOpType() 430 { 431 return LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST; 432 } 433 434 435 436 /** 437 * {@inheritDoc} 438 */ 439 @Override() 440 public ASN1Element encodeProtocolOp() 441 { 442 final ASN1Element credentials; 443 if (credentialsType == CRED_TYPE_SIMPLE) 444 { 445 credentials = simplePassword; 446 } 447 else 448 { 449 if (saslCredentials == null) 450 { 451 credentials = new ASN1Sequence(CRED_TYPE_SASL, 452 new ASN1OctetString(saslMechanism)); 453 } 454 else 455 { 456 credentials = new ASN1Sequence(CRED_TYPE_SASL, 457 new ASN1OctetString(saslMechanism), 458 saslCredentials); 459 } 460 } 461 462 return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST, 463 new ASN1Integer(version), 464 new ASN1OctetString(bindDN), 465 credentials); 466 } 467 468 469 470 /** 471 * Decodes the provided ASN.1 element as a bind request protocol op. 472 * 473 * @param element The ASN.1 element to be decoded. 474 * 475 * @return The decoded bind request protocol op. 476 * 477 * @throws LDAPException If the provided ASN.1 element cannot be decoded as 478 * a bind request protocol op. 479 */ 480 public static BindRequestProtocolOp decodeProtocolOp( 481 final ASN1Element element) 482 throws LDAPException 483 { 484 try 485 { 486 final ASN1Element[] elements = 487 ASN1Sequence.decodeAsSequence(element).elements(); 488 final int version = ASN1Integer.decodeAsInteger(elements[0]).intValue(); 489 final String bindDN = 490 ASN1OctetString.decodeAsOctetString(elements[1]).stringValue(); 491 492 final ASN1OctetString saslCredentials; 493 final ASN1OctetString simplePassword; 494 final String saslMechanism; 495 switch (elements[2].getType()) 496 { 497 case CRED_TYPE_SIMPLE: 498 simplePassword = ASN1OctetString.decodeAsOctetString(elements[2]); 499 saslMechanism = null; 500 saslCredentials = null; 501 break; 502 503 case CRED_TYPE_SASL: 504 final ASN1Element[] saslElements = 505 ASN1Sequence.decodeAsSequence(elements[2]).elements(); 506 saslMechanism = ASN1OctetString.decodeAsOctetString(saslElements[0]). 507 stringValue(); 508 if (saslElements.length == 1) 509 { 510 saslCredentials = null; 511 } 512 else 513 { 514 saslCredentials = 515 ASN1OctetString.decodeAsOctetString(saslElements[1]); 516 } 517 518 simplePassword = null; 519 break; 520 521 default: 522 throw new LDAPException(ResultCode.DECODING_ERROR, 523 ERR_BIND_REQUEST_INVALID_CRED_TYPE.get( 524 toHex(elements[2].getType()))); 525 } 526 527 return new BindRequestProtocolOp(version, bindDN, elements[2].getType(), 528 simplePassword, saslMechanism, saslCredentials); 529 } 530 catch (final LDAPException le) 531 { 532 debugException(le); 533 throw le; 534 } 535 catch (final Exception e) 536 { 537 debugException(e); 538 throw new LDAPException(ResultCode.DECODING_ERROR, 539 ERR_BIND_REQUEST_CANNOT_DECODE.get(getExceptionMessage(e)), 540 e); 541 } 542 } 543 544 545 546 /** 547 * {@inheritDoc} 548 */ 549 @Override() 550 public void writeTo(final ASN1Buffer buffer) 551 { 552 final ASN1BufferSequence opSequence = 553 buffer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST); 554 buffer.addInteger(version); 555 buffer.addOctetString(bindDN); 556 557 if (credentialsType == CRED_TYPE_SIMPLE) 558 { 559 buffer.addElement(simplePassword); 560 } 561 else 562 { 563 final ASN1BufferSequence saslSequence = 564 buffer.beginSequence(CRED_TYPE_SASL); 565 buffer.addOctetString(saslMechanism); 566 if (saslCredentials != null) 567 { 568 buffer.addElement(saslCredentials); 569 } 570 saslSequence.end(); 571 } 572 opSequence.end(); 573 buffer.setZeroBufferOnClear(); 574 } 575 576 577 578 /** 579 * Creates a new bind request object from this bind request protocol op. 580 * 581 * @param controls The set of controls to include in the bind request. It 582 * may be empty or {@code null} if no controls should be 583 * included. 584 * 585 * @return The bind request that was created. 586 */ 587 public BindRequest toBindRequest(final Control... controls) 588 { 589 if (credentialsType == CRED_TYPE_SIMPLE) 590 { 591 return new SimpleBindRequest(bindDN, simplePassword.getValue(), 592 controls); 593 } 594 else 595 { 596 return new GenericSASLBindRequest(bindDN, saslMechanism, 597 saslCredentials, controls); 598 } 599 } 600 601 602 603 /** 604 * Retrieves a string representation of this protocol op. 605 * 606 * @return A string representation of this protocol op. 607 */ 608 @Override() 609 public String toString() 610 { 611 final StringBuilder buffer = new StringBuilder(); 612 toString(buffer); 613 return buffer.toString(); 614 } 615 616 617 618 /** 619 * {@inheritDoc} 620 */ 621 @Override() 622 public void toString(final StringBuilder buffer) 623 { 624 buffer.append("BindRequestProtocolOp(version="); 625 buffer.append(version); 626 buffer.append(", bindDN='"); 627 buffer.append(bindDN); 628 buffer.append("', type="); 629 630 if (credentialsType == CRED_TYPE_SIMPLE) 631 { 632 buffer.append("simple"); 633 } 634 else 635 { 636 buffer.append("SASL, mechanism="); 637 buffer.append(saslMechanism); 638 } 639 640 buffer.append(')'); 641 } 642}