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