001 /*
002 * Copyright 2009-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2009-2014 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 }