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.Debug; 041import com.unboundid.util.InternalUseOnly; 042import com.unboundid.util.NotMutable; 043import com.unboundid.util.StaticUtils; 044import com.unboundid.util.ThreadSafety; 045import com.unboundid.util.ThreadSafetyLevel; 046import com.unboundid.util.Validator; 047 048import static com.unboundid.ldap.protocol.ProtocolMessages.*; 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 Validator.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 Validator.ensureNotNull(bindDN); 281 break; 282 283 case CRED_TYPE_SASL: 284 final ASN1StreamReaderSequence saslSequence = reader.beginSequence(); 285 saslMechanism = reader.readString(); 286 Validator.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( 301 StaticUtils.toHex(credentialsType))); 302 } 303 } 304 catch (final LDAPException le) 305 { 306 Debug.debugException(le); 307 throw le; 308 } 309 catch (final Exception e) 310 { 311 Debug.debugException(e); 312 313 throw new LDAPException(ResultCode.DECODING_ERROR, 314 ERR_BIND_REQUEST_CANNOT_DECODE.get( 315 StaticUtils.getExceptionMessage(e)), 316 e); 317 } 318 } 319 320 321 322 /** 323 * Creates a new bind request protocol op with the provided information. 324 * 325 * @param version The protocol version. 326 * @param bindDN The bind DN. It must not be {@code null} (but may 327 * be empty). 328 * @param credentialsType The type of credentials supplied. 329 * @param simplePassword The password for simple authentication, if 330 * appropriate. 331 * @param saslMechanism The name of the SASL mechanism, if appropriate. 332 * @param saslCredentials The SASL credentials, if appropriate. 333 */ 334 private BindRequestProtocolOp(final int version, final String bindDN, 335 final byte credentialsType, 336 final ASN1OctetString simplePassword, 337 final String saslMechanism, 338 final ASN1OctetString saslCredentials) 339 { 340 this.version = version; 341 this.bindDN = bindDN; 342 this.credentialsType = credentialsType; 343 this.simplePassword = simplePassword; 344 this.saslMechanism = saslMechanism; 345 this.saslCredentials = saslCredentials; 346 } 347 348 349 350 /** 351 * Retrieves the protocol version for this bind request. 352 * 353 * @return The protocol version for this bind request. 354 */ 355 public int getVersion() 356 { 357 return version; 358 } 359 360 361 362 /** 363 * Retrieves the bind DN for this bind request. 364 * 365 * @return The bind DN for this bind request, or an empty string if none was 366 * provided. 367 */ 368 public String getBindDN() 369 { 370 return bindDN; 371 } 372 373 374 375 /** 376 * Retrieves the credentials type for this bind request. It will either be 377 * {@link #CRED_TYPE_SIMPLE} or {@link #CRED_TYPE_SASL}. 378 * 379 * @return The credentials type for this bind request. 380 */ 381 public byte getCredentialsType() 382 { 383 return credentialsType; 384 } 385 386 387 388 /** 389 * Retrieves the password to use for simple authentication. 390 * 391 * @return The password to use for simple authentication, or {@code null} if 392 * SASL authentication will be used. 393 */ 394 public ASN1OctetString getSimplePassword() 395 { 396 return simplePassword; 397 } 398 399 400 401 /** 402 * Retrieves the name of the SASL mechanism for this bind request. 403 * 404 * @return The name of the SASL mechanism for this bind request, or 405 * {@code null} if simple authentication will be used. 406 */ 407 public String getSASLMechanism() 408 { 409 return saslMechanism; 410 } 411 412 413 414 /** 415 * Retrieves the credentials to use for SASL authentication, if any. 416 * 417 * @return The credentials to use for SASL authentication, or {@code null} if 418 * there are no SASL credentials or if simple authentication will be 419 * used. 420 */ 421 public ASN1OctetString getSASLCredentials() 422 { 423 return saslCredentials; 424 } 425 426 427 428 /** 429 * {@inheritDoc} 430 */ 431 @Override() 432 public byte getProtocolOpType() 433 { 434 return LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST; 435 } 436 437 438 439 /** 440 * {@inheritDoc} 441 */ 442 @Override() 443 public ASN1Element encodeProtocolOp() 444 { 445 final ASN1Element credentials; 446 if (credentialsType == CRED_TYPE_SIMPLE) 447 { 448 credentials = simplePassword; 449 } 450 else 451 { 452 if (saslCredentials == null) 453 { 454 credentials = new ASN1Sequence(CRED_TYPE_SASL, 455 new ASN1OctetString(saslMechanism)); 456 } 457 else 458 { 459 credentials = new ASN1Sequence(CRED_TYPE_SASL, 460 new ASN1OctetString(saslMechanism), 461 saslCredentials); 462 } 463 } 464 465 return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST, 466 new ASN1Integer(version), 467 new ASN1OctetString(bindDN), 468 credentials); 469 } 470 471 472 473 /** 474 * Decodes the provided ASN.1 element as a bind request protocol op. 475 * 476 * @param element The ASN.1 element to be decoded. 477 * 478 * @return The decoded bind request protocol op. 479 * 480 * @throws LDAPException If the provided ASN.1 element cannot be decoded as 481 * a bind request protocol op. 482 */ 483 public static BindRequestProtocolOp decodeProtocolOp( 484 final ASN1Element element) 485 throws LDAPException 486 { 487 try 488 { 489 final ASN1Element[] elements = 490 ASN1Sequence.decodeAsSequence(element).elements(); 491 final int version = ASN1Integer.decodeAsInteger(elements[0]).intValue(); 492 final String bindDN = 493 ASN1OctetString.decodeAsOctetString(elements[1]).stringValue(); 494 495 final ASN1OctetString saslCredentials; 496 final ASN1OctetString simplePassword; 497 final String saslMechanism; 498 switch (elements[2].getType()) 499 { 500 case CRED_TYPE_SIMPLE: 501 simplePassword = ASN1OctetString.decodeAsOctetString(elements[2]); 502 saslMechanism = null; 503 saslCredentials = null; 504 break; 505 506 case CRED_TYPE_SASL: 507 final ASN1Element[] saslElements = 508 ASN1Sequence.decodeAsSequence(elements[2]).elements(); 509 saslMechanism = ASN1OctetString.decodeAsOctetString(saslElements[0]). 510 stringValue(); 511 if (saslElements.length == 1) 512 { 513 saslCredentials = null; 514 } 515 else 516 { 517 saslCredentials = 518 ASN1OctetString.decodeAsOctetString(saslElements[1]); 519 } 520 521 simplePassword = null; 522 break; 523 524 default: 525 throw new LDAPException(ResultCode.DECODING_ERROR, 526 ERR_BIND_REQUEST_INVALID_CRED_TYPE.get( 527 StaticUtils.toHex(elements[2].getType()))); 528 } 529 530 return new BindRequestProtocolOp(version, bindDN, elements[2].getType(), 531 simplePassword, saslMechanism, saslCredentials); 532 } 533 catch (final LDAPException le) 534 { 535 Debug.debugException(le); 536 throw le; 537 } 538 catch (final Exception e) 539 { 540 Debug.debugException(e); 541 throw new LDAPException(ResultCode.DECODING_ERROR, 542 ERR_BIND_REQUEST_CANNOT_DECODE.get( 543 StaticUtils.getExceptionMessage(e)), 544 e); 545 } 546 } 547 548 549 550 /** 551 * {@inheritDoc} 552 */ 553 @Override() 554 public void writeTo(final ASN1Buffer buffer) 555 { 556 final ASN1BufferSequence opSequence = 557 buffer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST); 558 buffer.addInteger(version); 559 buffer.addOctetString(bindDN); 560 561 if (credentialsType == CRED_TYPE_SIMPLE) 562 { 563 buffer.addElement(simplePassword); 564 } 565 else 566 { 567 final ASN1BufferSequence saslSequence = 568 buffer.beginSequence(CRED_TYPE_SASL); 569 buffer.addOctetString(saslMechanism); 570 if (saslCredentials != null) 571 { 572 buffer.addElement(saslCredentials); 573 } 574 saslSequence.end(); 575 } 576 opSequence.end(); 577 buffer.setZeroBufferOnClear(); 578 } 579 580 581 582 /** 583 * Creates a new bind request object from this bind request protocol op. 584 * 585 * @param controls The set of controls to include in the bind request. It 586 * may be empty or {@code null} if no controls should be 587 * included. 588 * 589 * @return The bind request that was created. 590 */ 591 public BindRequest toBindRequest(final Control... controls) 592 { 593 if (credentialsType == CRED_TYPE_SIMPLE) 594 { 595 return new SimpleBindRequest(bindDN, simplePassword.getValue(), 596 controls); 597 } 598 else 599 { 600 return new GenericSASLBindRequest(bindDN, saslMechanism, 601 saslCredentials, controls); 602 } 603 } 604 605 606 607 /** 608 * Retrieves a string representation of this protocol op. 609 * 610 * @return A string representation of this protocol op. 611 */ 612 @Override() 613 public String toString() 614 { 615 final StringBuilder buffer = new StringBuilder(); 616 toString(buffer); 617 return buffer.toString(); 618 } 619 620 621 622 /** 623 * {@inheritDoc} 624 */ 625 @Override() 626 public void toString(final StringBuilder buffer) 627 { 628 buffer.append("BindRequestProtocolOp(version="); 629 buffer.append(version); 630 buffer.append(", bindDN='"); 631 buffer.append(bindDN); 632 buffer.append("', type="); 633 634 if (credentialsType == CRED_TYPE_SIMPLE) 635 { 636 buffer.append("simple"); 637 } 638 else 639 { 640 buffer.append("SASL, mechanism="); 641 buffer.append(saslMechanism); 642 } 643 644 buffer.append(')'); 645 } 646}