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