001 /*
002 * Copyright 2015 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2015 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.sdk.unboundidds.extensions;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Collections;
027 import java.util.Iterator;
028 import java.util.List;
029
030 import com.unboundid.asn1.ASN1Boolean;
031 import com.unboundid.asn1.ASN1Element;
032 import com.unboundid.asn1.ASN1Long;
033 import com.unboundid.asn1.ASN1OctetString;
034 import com.unboundid.asn1.ASN1Sequence;
035 import com.unboundid.ldap.sdk.Control;
036 import com.unboundid.ldap.sdk.ExtendedRequest;
037 import com.unboundid.ldap.sdk.ExtendedResult;
038 import com.unboundid.ldap.sdk.LDAPConnection;
039 import com.unboundid.ldap.sdk.LDAPException;
040 import com.unboundid.ldap.sdk.ResultCode;
041 import com.unboundid.util.Debug;
042 import com.unboundid.util.NotMutable;
043 import com.unboundid.util.ObjectPair;
044 import com.unboundid.util.StaticUtils;
045 import com.unboundid.util.ThreadSafety;
046 import com.unboundid.util.ThreadSafetyLevel;
047 import com.unboundid.util.Validator;
048
049 import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
050
051
052
053 /**
054 * <BLOCKQUOTE>
055 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
056 * LDAP SDK for Java. It is not available for use in applications that
057 * include only the Standard Edition of the LDAP SDK, and is not supported for
058 * use in conjunction with non-UnboundID products.
059 * </BLOCKQUOTE>
060 * This class provides an implementation of an extended request that can be used
061 * to trigger the delivery of a temporary single-use token to a specified user
062 * via some out-of-band mechanism. It can be used for security purposes
063 * (e.g., as part of step-up authentication), for data validation purposes
064 * (e.g., to verify that a user can receive e-mail messages at a given address
065 * or SMS messages at a given phone number), or for other purposes in which it
066 * could be useful to deliver and consume a token through some out-of-band
067 * mechanism.
068 * <BR><BR>
069 * This extended request has an OID of "1.3.6.1.4.1.30221.2.6.49" and it must
070 * have a value with the following encoding:
071 * <PRE>
072 * DeliverSingleUseTokenRequestValue ::= SEQUENCE {
073 * userDN LDAPDN,
074 * tokenID OCTET STRING,
075 * validityDurationMillis [0] INTEGER OPTIONAL,
076 * messageSubject [1] OCTET STRING OPTIONAL,
077 * fullTextBeforeToken [2] OCTET STRING OPTIONAL,
078 * fullTextAfterToken [3] OCTET STRING OPTIONAL,
079 * compactTextBeforeToken [4] OCTET STRING OPTIONAL,
080 * compactTextAfterToken [5] OCTET STRING OPTIONAL,
081 * preferredDeliveryMechanism [6] SEQUENCE OF SEQUENCE {
082 * mechanismName OCTET STRING,
083 * recipientID OCTET STRING OPTIONAL },
084 * deliverIfPasswordExpired [7] BOOLEAN DEFAULT FALSE,
085 * deliverIfAccountLocked [8] BOOLEAN DEFAULT FALSE,
086 * deliverIfAccountDisabled [9] BOOLEAN DEFAULT FALSE,
087 * deliverIfAccountExpired [10] BOOLEAN DEFAULT FALSE,
088 * ... }
089 * </PRE>
090 *
091 * @see DeliverSingleUseTokenExtendedResult
092 * @see ConsumeSingleUseTokenExtendedRequest
093 */
094 @NotMutable()
095 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
096 public final class DeliverSingleUseTokenExtendedRequest
097 extends ExtendedRequest
098 {
099 /**
100 * The OID (1.3.6.1.4.1.30221.2.6.49) for the deliver single-use token
101 * extended request.
102 */
103 public static final String DELIVER_SINGLE_USE_TOKEN_REQUEST_OID =
104 "1.3.6.1.4.1.30221.2.6.49";
105
106
107
108 /**
109 * The BER type for the "validity duration millis" element of the value
110 * sequence.
111 */
112 private static final byte VALIDITY_DURATION_MILLIS_BER_TYPE = (byte) 0x80;
113
114
115
116 /**
117 * The BER type for the "message subject" element of the value sequence.
118 */
119 private static final byte MESSAGE_SUBJECT_BER_TYPE = (byte) 0x81;
120
121
122
123 /**
124 * The BER type for the "full text before token" element of the value
125 * sequence.
126 */
127 private static final byte FULL_TEXT_BEFORE_TOKEN_BER_TYPE = (byte) 0x82;
128
129
130
131 /**
132 * The BER type for the "full text after token" element of the value
133 * sequence.
134 */
135 private static final byte FULL_TEXT_AFTER_TOKEN_BER_TYPE = (byte) 0x83;
136
137
138
139 /**
140 * The BER type for the "compact text before token" element of the value
141 * sequence.
142 */
143 private static final byte COMPACT_TEXT_BEFORE_TOKEN_BER_TYPE = (byte) 0x84;
144
145
146
147 /**
148 * The BER type for the "compact text after token" element of the value
149 * sequence.
150 */
151 private static final byte COMPACT_TEXT_AFTER_TOKEN_BER_TYPE = (byte) 0x85;
152
153
154
155 /**
156 * The BER type for the "preferred delivery mechanism" element of the value
157 * sequence.
158 */
159 private static final byte PREFERRED_DELIVERY_MECHANISM_BER_TYPE = (byte) 0xA6;
160
161
162
163 /**
164 * The BER type for the "deliver if password expired" element of the value
165 * sequence.
166 */
167 private static final byte DELIVER_IF_PASSWORD_EXPIRED_TYPE = (byte) 0x87;
168
169
170
171 /**
172 * The BER type for the "deliver if account locked" element of the value
173 * sequence.
174 */
175 private static final byte DELIVER_IF_ACCOUNT_LOCKED_TYPE = (byte) 0x88;
176
177
178
179 /**
180 * The BER type for the "deliver if account disabled" element of the value
181 * sequence.
182 */
183 private static final byte DELIVER_IF_ACCOUNT_DISABLED_TYPE = (byte) 0x89;
184
185
186
187 /**
188 * The BER type for the "deliver if account expired" element of the value
189 * sequence.
190 */
191 private static final byte DELIVER_IF_ACCOUNT_EXPIRED_TYPE = (byte) 0x8A;
192
193
194
195 /**
196 * The serial version UID for this serializable class.
197 */
198 private static final long serialVersionUID = -4158226639899928825L;
199
200
201
202 // Indicates whether the server should attempt to deliver the token if the
203 // target user's account has been administratively disabled.
204 private final boolean deliverIfAccountDisabled;
205
206 // Indicates whether the server should attempt to deliver the token if the
207 // target user's account has expired.
208 private final boolean deliverIfAccountExpired;
209
210 // Indicates whether the server should attempt to deliver the token if the
211 // target user's account has been locked for some reason.
212 private final boolean deliverIfAccountLocked;
213
214 // Indicates whether the server should attempt to deliver the token if the
215 // target user's password is expired.
216 private final boolean deliverIfPasswordExpired;
217
218 // An optional list of the preferred delivery mechanisms that should be used.
219 private final List<ObjectPair<String,String>> preferredDeliveryMechanisms;
220
221 // The maximum length of time, in milliseconds, that the token should be
222 // considered valid.
223 private final Long validityDurationMillis;
224
225 // The text to include after the token in a compact message.
226 private final String compactTextAfterToken;
227
228 // The text to include before the token in a compact message.
229 private final String compactTextBeforeToken;
230
231 // The text to include after the token in a message without size constraints.
232 private final String fullTextAfterToken;
233
234 // The text to include before the token in a message without size constraints.
235 private final String fullTextBeforeToken;
236
237 // The text to use as the message subject.
238 private final String messageSubject;
239
240 // The identifier that will be used when consuming this token.
241 private final String tokenID;
242
243 // The DN of the user for whom the token should be generated and delivered.
244 private final String userDN;
245
246
247
248 /**
249 * Creates a new deliver single-use token extended request with the provided
250 * information.
251 *
252 * @param userDN The DN of the user for whom the token
253 * should be generated and delivered. It
254 * must not be {@code null}.
255 * @param tokenID An identifier for the token, which can
256 * differentiate between separate uses of
257 * this extended operation for different
258 * purposes. This token ID should be
259 * provided in the request to consume the
260 * token that has been delivered. It
261 * must not be {@code null}.
262 * @param validityDurationMillis The maximum length of time in
263 * milliseconds that the generated token
264 * should be considered valid. It may be
265 * {@code null} if the server should
266 * determine the token validity duration.
267 * If it is non-{@code null}, then the
268 * value must be greater than zero.
269 * @param messageSubject The text (if any) that should be used
270 * as the message subject if the delivery
271 * mechanism accepts a subject. This may
272 * be {@code null} if no subject is
273 * required or a subject should be
274 * automatically generated.
275 * @param fullTextBeforeToken The text (if any) that should appear
276 * before the generated single-use token
277 * in the message delivered to the user
278 * via a delivery mechanism that does not
279 * impose significant constraints on
280 * message size. This may be
281 * {@code null} if no text is required
282 * before the token.
283 * @param fullTextAfterToken The text (if any) that should appear
284 * after the generated single-use token
285 * in the message delivered to the user
286 * via a delivery mechanism that does not
287 * impose significant constraints on
288 * message size. This may be
289 * {@code null} if no text is required
290 * after the token.
291 * @param compactTextBeforeToken The text (if any) that should appear
292 * before the generated single-use token
293 * in the message delivered to the user
294 * via a delivery mechanism that imposes
295 * significant constraints on message
296 * size. This may be {@code null} if no
297 * text is required before the token.
298 * @param compactTextAfterToken The text (if any) that should appear
299 * after the generated single-use token
300 * in the message delivered to the user
301 * via a delivery mechanism that imposes
302 * significant constraints on message
303 * size. This may be {@code null} if no
304 * text is required after the token.
305 * @param preferredDeliveryMechanisms An optional list of the preferred
306 * delivery mechanisms that should be
307 * used to convey the token to the target
308 * user. It may be {@code null} or empty
309 * if the server should determine the
310 * delivery mechanisms to attempt. If
311 * a list of preferred delivery
312 * mechanisms is provided, the server
313 * will only attempt to deliver the token
314 * through these mechanisms, with
315 * attempts made in the order specified
316 * in this list.
317 * @param deliverIfPasswordExpired Indicates whether to generate and
318 * deliver a token if the target user's
319 * password is expired.
320 * @param deliverIfAccountLocked Indicates whether to generate and
321 * deliver a token if the target user's
322 * account is locked for some reason
323 * (e.g., too many failed authentication
324 * attempts, the account has been idle
325 * for too long, the user failed to
326 * change his/her password in a timely
327 * manner after an administrative reset,
328 * etc.).
329 * @param deliverIfAccountDisabled Indicates whether to generate and
330 * deliver a token if the target user's
331 * account has been disabled by an
332 * administrator.
333 * @param deliverIfAccountExpired Indicates whether to generate and
334 * deliver a token if the target user's
335 * account has expired.
336 * @param controls An optional set of controls to include
337 * in the request. It may be
338 * {@code null} or empty if no controls
339 * are required.
340 */
341 public DeliverSingleUseTokenExtendedRequest(final String userDN,
342 final String tokenID, final Long validityDurationMillis,
343 final String messageSubject, final String fullTextBeforeToken,
344 final String fullTextAfterToken,
345 final String compactTextBeforeToken,
346 final String compactTextAfterToken,
347 final List<ObjectPair<String,String>> preferredDeliveryMechanisms,
348 final boolean deliverIfPasswordExpired,
349 final boolean deliverIfAccountLocked,
350 final boolean deliverIfAccountDisabled,
351 final boolean deliverIfAccountExpired, final Control... controls)
352 {
353 super(DELIVER_SINGLE_USE_TOKEN_REQUEST_OID,
354 encodeValue(userDN, tokenID, validityDurationMillis, messageSubject,
355 fullTextBeforeToken, fullTextAfterToken, compactTextBeforeToken,
356 compactTextAfterToken, preferredDeliveryMechanisms,
357 deliverIfPasswordExpired, deliverIfAccountLocked,
358 deliverIfAccountDisabled, deliverIfAccountExpired),
359 controls);
360
361 this.userDN = userDN;
362 this.tokenID = tokenID;
363 this.validityDurationMillis = validityDurationMillis;
364 this.messageSubject = messageSubject;
365 this.fullTextBeforeToken = fullTextBeforeToken;
366 this.fullTextAfterToken = fullTextAfterToken;
367 this.compactTextBeforeToken = compactTextBeforeToken;
368 this.compactTextAfterToken = compactTextAfterToken;
369 this.deliverIfPasswordExpired = deliverIfPasswordExpired;
370 this.deliverIfAccountLocked = deliverIfAccountLocked;
371 this.deliverIfAccountDisabled = deliverIfAccountDisabled;
372 this.deliverIfAccountExpired = deliverIfAccountExpired;
373
374 if (preferredDeliveryMechanisms == null)
375 {
376 this.preferredDeliveryMechanisms = Collections.emptyList();
377 }
378 else
379 {
380 this.preferredDeliveryMechanisms = Collections.unmodifiableList(
381 new ArrayList<ObjectPair<String,String>>(
382 preferredDeliveryMechanisms));
383 }
384 }
385
386
387
388 /**
389 * Decodes the provided extended request as a deliver single-use token
390 * extended request.
391 *
392 * @param request The extended request to decode as a deliver single-use
393 * token extended request.
394 *
395 * @throws LDAPException If the provided extended request cannot be decoded
396 * as a deliver single-use token request.
397 */
398 public DeliverSingleUseTokenExtendedRequest(final ExtendedRequest request)
399 throws LDAPException
400 {
401 super(request);
402
403 final ASN1OctetString value = request.getValue();
404 if (value == null)
405 {
406 throw new LDAPException(ResultCode.DECODING_ERROR,
407 ERR_DELIVER_SINGLE_USE_TOKEN_REQUEST_NO_VALUE.get());
408 }
409
410 try
411 {
412 final ASN1Element[] elements =
413 ASN1Sequence.decodeAsSequence(value.getValue()).elements();
414 userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
415 tokenID = ASN1OctetString.decodeAsOctetString(elements[1]).stringValue();
416
417 Long validityDuration = null;
418 String subject = null;
419 String fullBefore = null;
420 String fullAfter = null;
421 String compactBefore = null;
422 String compactAfter = null;
423 final ArrayList<ObjectPair<String,String>> pdmList =
424 new ArrayList<ObjectPair<String,String>>(10);
425 boolean ifPasswordExpired = false;
426 boolean ifAccountLocked = false;
427 boolean ifAccountDisabled = false;
428 boolean ifAccountExpired = false;
429 for (int i=2; i < elements.length; i++)
430 {
431 switch (elements[i].getType())
432 {
433 case VALIDITY_DURATION_MILLIS_BER_TYPE:
434 validityDuration = ASN1Long.decodeAsLong(elements[i]).longValue();
435 break;
436
437 case MESSAGE_SUBJECT_BER_TYPE:
438 subject =
439 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
440 break;
441
442 case FULL_TEXT_BEFORE_TOKEN_BER_TYPE:
443 fullBefore =
444 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
445 break;
446
447 case FULL_TEXT_AFTER_TOKEN_BER_TYPE:
448 fullAfter =
449 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
450 break;
451
452 case COMPACT_TEXT_BEFORE_TOKEN_BER_TYPE:
453 compactBefore =
454 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
455 break;
456
457 case COMPACT_TEXT_AFTER_TOKEN_BER_TYPE:
458 compactAfter =
459 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
460 break;
461
462 case PREFERRED_DELIVERY_MECHANISM_BER_TYPE:
463 for (final ASN1Element pdmElement :
464 ASN1Sequence.decodeAsSequence(elements[i]).elements())
465 {
466 final ASN1Element[] dmElements =
467 ASN1Sequence.decodeAsSequence(pdmElement).elements();
468 final String name = ASN1OctetString.decodeAsOctetString(
469 dmElements[0]).stringValue();
470
471 final String recipientID;
472 if (dmElements.length > 1)
473 {
474 recipientID = ASN1OctetString.decodeAsOctetString(
475 dmElements[1]).stringValue();
476 }
477 else
478 {
479 recipientID = null;
480 }
481 pdmList.add(new ObjectPair<String,String>(name, recipientID));
482 }
483 break;
484
485 case DELIVER_IF_PASSWORD_EXPIRED_TYPE:
486 ifPasswordExpired =
487 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
488 break;
489
490 case DELIVER_IF_ACCOUNT_LOCKED_TYPE:
491 ifAccountLocked =
492 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
493 break;
494
495 case DELIVER_IF_ACCOUNT_DISABLED_TYPE:
496 ifAccountDisabled =
497 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
498 break;
499
500 case DELIVER_IF_ACCOUNT_EXPIRED_TYPE:
501 ifAccountExpired =
502 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
503 break;
504
505 default:
506 throw new LDAPException(ResultCode.DECODING_ERROR,
507 ERR_DELIVER_SINGLE_USE_TOKEN_REQUEST_UNKNOWN_ELEMENT.get(
508 StaticUtils.toHex(elements[i].getType())));
509 }
510 }
511
512 validityDurationMillis = validityDuration;
513 messageSubject = subject;
514 fullTextBeforeToken = fullBefore;
515 fullTextAfterToken = fullAfter;
516 compactTextBeforeToken = compactBefore;
517 compactTextAfterToken = compactAfter;
518 preferredDeliveryMechanisms = Collections.unmodifiableList(pdmList);
519 deliverIfPasswordExpired = ifPasswordExpired;
520 deliverIfAccountLocked = ifAccountLocked;
521 deliverIfAccountDisabled = ifAccountDisabled;
522 deliverIfAccountExpired = ifAccountExpired;
523 }
524 catch (final LDAPException le)
525 {
526 Debug.debugException(le);
527 throw le;
528 }
529 catch (final Exception e)
530 {
531 Debug.debugException(e);
532 throw new LDAPException(ResultCode.DECODING_ERROR,
533 ERR_DELIVER_SINGLE_USE_TOKEN_REQUEST_CANNOT_DECODE.get(
534 StaticUtils.getExceptionMessage(e)),
535 e);
536 }
537 }
538
539
540
541 /**
542 * Encodes the provided information into an ASN.1 octet string suitable for
543 * use as the value of the extended request.
544 *
545 * @param userDN The DN of the user for whom the token
546 * should be generated and delivered. It
547 * must not be {@code null}.
548 * @param tokenID An identifier for the token, which can
549 * differentiate between separate uses of
550 * this extended operation for different
551 * purposes. This token ID should be
552 * provided in the request to consume the
553 * token that has been delivered. It
554 * must not be {@code null}.
555 * @param validityDurationMillis The maximum length of time in
556 * milliseconds that the generated token
557 * should be considered valid. It may be
558 * {@code null} if the server should
559 * determine the token validity duration.
560 * If it is non-{@code null}, then the
561 * value must be greater than zero.
562 * @param messageSubject The text (if any) that should be used
563 * as the message subject if the delivery
564 * mechanism accepts a subject. This may
565 * be {@code null} if no subject is
566 * required or a subject should be
567 * automatically generated.
568 * @param fullTextBeforeToken The text (if any) that should appear
569 * before the generated single-use token
570 * in the message delivered to the user
571 * via a delivery mechanism that does not
572 * impose significant constraints on
573 * message size. This may be
574 * {@code null} if no text is required
575 * before the token.
576 * @param fullTextAfterToken The text (if any) that should appear
577 * after the generated single-use token
578 * in the message delivered to the user
579 * via a delivery mechanism that does not
580 * impose significant constraints on
581 * message size. This may be
582 * {@code null} if no text is required
583 * after the token.
584 * @param compactTextBeforeToken The text (if any) that should appear
585 * before the generated single-use token
586 * in the message delivered to the user
587 * via a delivery mechanism that imposes
588 * significant constraints on message
589 * size. This may be {@code null} if no
590 * text is required before the token.
591 * @param compactTextAfterToken The text (if any) that should appear
592 * after the generated single-use token
593 * in the message delivered to the user
594 * via a delivery mechanism that imposes
595 * significant constraints on message
596 * size. This may be {@code null} if no
597 * text is required after the token.
598 * @param preferredDeliveryMechanisms An optional list of the preferred
599 * delivery mechanisms that should be
600 * used to convey the token to the target
601 * user. It may be {@code null} or empty
602 * if the server should determine the
603 * delivery mechanisms to attempt. If
604 * a list of preferred delivery
605 * mechanisms is provided, the server
606 * will only attempt to deliver the token
607 * through these mechanisms, with
608 * attempts made in the order specified
609 * in this list.
610 * @param deliverIfPasswordExpired Indicates whether to generate and
611 * deliver a token if the target user's
612 * password is expired.
613 * @param deliverIfAccountLocked Indicates whether to generate and
614 * deliver a token if the target user's
615 * account is locked for some reason
616 * (e.g., too many failed authentication
617 * attempts, the account has been idle
618 * for too long, the user failed to
619 * change his/her password in a timely
620 * manner after an administrative reset,
621 * etc.).
622 * @param deliverIfAccountDisabled Indicates whether to generate and
623 * deliver a token if the target user's
624 * account has been disabled by an
625 * administrator.
626 * @param deliverIfAccountExpired Indicates whether to generate and
627 * deliver a token if the target user's
628 * account has expired.
629 *
630 * @return An ASN.1 octet string containing the encoded value.
631 */
632 private static ASN1OctetString encodeValue(final String userDN,
633 final String tokenID, final Long validityDurationMillis,
634 final String messageSubject, final String fullTextBeforeToken,
635 final String fullTextAfterToken, final String compactTextBeforeToken,
636 final String compactTextAfterToken,
637 final List<ObjectPair<String,String>> preferredDeliveryMechanisms,
638 final boolean deliverIfPasswordExpired,
639 final boolean deliverIfAccountLocked,
640 final boolean deliverIfAccountDisabled,
641 final boolean deliverIfAccountExpired)
642 {
643 Validator.ensureNotNull(userDN);
644 Validator.ensureNotNull(tokenID);
645
646 if (validityDurationMillis != null)
647 {
648 Validator.ensureTrue(validityDurationMillis > 0L);
649 }
650
651
652 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(13);
653 elements.add(new ASN1OctetString(userDN));
654 elements.add(new ASN1OctetString(tokenID));
655
656 if (validityDurationMillis != null)
657 {
658 elements.add(new ASN1Long(VALIDITY_DURATION_MILLIS_BER_TYPE,
659 validityDurationMillis));
660 }
661
662 if (messageSubject != null)
663 {
664 elements.add(new ASN1OctetString(MESSAGE_SUBJECT_BER_TYPE,
665 messageSubject));
666 }
667
668 if (fullTextBeforeToken != null)
669 {
670 elements.add(new ASN1OctetString(FULL_TEXT_BEFORE_TOKEN_BER_TYPE,
671 fullTextBeforeToken));
672 }
673
674 if (fullTextAfterToken != null)
675 {
676 elements.add(new ASN1OctetString(FULL_TEXT_AFTER_TOKEN_BER_TYPE,
677 fullTextAfterToken));
678 }
679
680 if (compactTextBeforeToken != null)
681 {
682 elements.add(new ASN1OctetString(COMPACT_TEXT_BEFORE_TOKEN_BER_TYPE,
683 compactTextBeforeToken));
684 }
685
686 if (compactTextAfterToken != null)
687 {
688 elements.add(new ASN1OctetString(COMPACT_TEXT_AFTER_TOKEN_BER_TYPE,
689 compactTextAfterToken));
690 }
691
692 if ((preferredDeliveryMechanisms != null) &&
693 (! preferredDeliveryMechanisms.isEmpty()))
694 {
695 final ArrayList<ASN1Element> pdmElements =
696 new ArrayList<ASN1Element>(preferredDeliveryMechanisms.size());
697 for (final ObjectPair<String,String> p : preferredDeliveryMechanisms)
698 {
699 final ArrayList<ASN1Element> l = new ArrayList<ASN1Element>(2);
700 l.add(new ASN1OctetString(p.getFirst()));
701 if (p.getSecond() != null)
702 {
703 l.add(new ASN1OctetString(p.getSecond()));
704 }
705 pdmElements.add(new ASN1Sequence(l));
706 }
707 elements.add(new ASN1Sequence(PREFERRED_DELIVERY_MECHANISM_BER_TYPE,
708 pdmElements));
709 }
710
711 if (deliverIfPasswordExpired)
712 {
713 elements.add(new ASN1Boolean(DELIVER_IF_PASSWORD_EXPIRED_TYPE, true));
714 }
715
716 if (deliverIfAccountLocked)
717 {
718 elements.add(new ASN1Boolean(DELIVER_IF_ACCOUNT_LOCKED_TYPE, true));
719 }
720
721 if (deliverIfAccountDisabled)
722 {
723 elements.add(new ASN1Boolean(DELIVER_IF_ACCOUNT_DISABLED_TYPE, true));
724 }
725
726 if (deliverIfAccountExpired)
727 {
728 elements.add(new ASN1Boolean(DELIVER_IF_ACCOUNT_EXPIRED_TYPE, true));
729 }
730
731 return new ASN1OctetString(new ASN1Sequence(elements).encode());
732 }
733
734
735
736 /**
737 * Retrieves the DN of the user for whom the token should be generated and
738 * delivered.
739 *
740 * @return The DN of the user for whom the token should be generated and
741 * delivered.
742 */
743 public String getUserDN()
744 {
745 return userDN;
746 }
747
748
749
750 /**
751 * Retrieves an identifier for the token, which can differentiate between
752 * separate uses of this extended operation for different purposes, and should
753 * be provided when consuming the token via the
754 * {@link ConsumeSingleUseTokenExtendedRequest}.
755 *
756 * @return An identifier for the token.
757 */
758 public String getTokenID()
759 {
760 return tokenID;
761 }
762
763
764
765 /**
766 * Retrieves the maximum length of time in milliseconds that the generated
767 * token should be considered valid, if defined. An attempt to consume the
768 * token after this length of time has elapsed will fail.
769 *
770 * @return The maximum length of time in milliseconds that the generated
771 * token should be considered valid, or {@code null} if the client
772 * did not specify a value and the token validity duration will be
773 * determined by the server.
774 */
775 public Long getValidityDurationMillis()
776 {
777 return validityDurationMillis;
778 }
779
780
781
782 /**
783 * Retrieves the text (if any) that should be used as the message subject for
784 * delivery mechanisms that can make use of a subject.
785 *
786 * @return The text that should be used as the message subject for delivery
787 * mechanisms that can make use of a subject, or {@code null} if no
788 * subject should be used, or if the delivery mechanism should
789 * attempt to automatically determine a subject.
790 */
791 public String getMessageSubject()
792 {
793 return messageSubject;
794 }
795
796
797
798 /**
799 * Retrieves the text (if any) that should appear before the single-use token
800 * in the message delivered to the user via a mechanism that does not impose
801 * significant constraints on message size.
802 *
803 * @return The text that should appear before the single-use token in the
804 * message delivered to the user via a mechanism that does not impose
805 * significant constraints on message size, or {@code null} if there
806 * should not be any text before the token.
807 */
808 public String getFullTextBeforeToken()
809 {
810 return fullTextBeforeToken;
811 }
812
813
814
815 /**
816 * Retrieves the text (if any) that should appear after the single-use token
817 * in the message delivered to the user via a mechanism that does not impose
818 * significant constraints on message size.
819 *
820 * @return The text that should appear after the single-use token in the
821 * message delivered to the user via a mechanism that does not impose
822 * significant constraints on message size, or {@code null} if there
823 * should not be any text after the token.
824 */
825 public String getFullTextAfterToken()
826 {
827 return fullTextAfterToken;
828 }
829
830
831
832 /**
833 * Retrieves the text (if any) that should appear before the single-use token
834 * in the message delivered to the user via a mechanism that imposes
835 * significant constraints on message size.
836 *
837 * @return The text that should appear before the single-use token in the
838 * message delivered to the user via a mechanism that imposes
839 * significant constraints on message size, or {@code null} if there
840 * should not be any text before the token.
841 */
842 public String getCompactTextBeforeToken()
843 {
844 return compactTextBeforeToken;
845 }
846
847
848
849 /**
850 * Retrieves the text (if any) that should appear after the single-use token
851 * in the message delivered to the user via a mechanism that imposes
852 * significant constraints on message size.
853 *
854 * @return The text that should appear after the single-use token in the
855 * message delivered to the user via a mechanism that imposes
856 * significant constraints on message size, or {@code null} if there
857 * should not be any text after the token.
858 */
859 public String getCompactTextAfterToken()
860 {
861 return compactTextAfterToken;
862 }
863
864
865
866 /**
867 * Retrieves a list of the preferred delivery mechanisms that should be used
868 * to provide the generated token to the target user. If the returned list is
869 * empty, then the server will attempt to determine which mechanism(s) to use
870 * and in which order to try them. If this list is not empty, then the server
871 * will only attempt the specified mechanisms and in the order in which they
872 * are listed.
873 *
874 * @return A list of the preferred delivery mechanisms that should be used to
875 * provide the generated token to the target user, or an empty list
876 * if the server should determine the delivery mechanisms to attempt.
877 */
878 public List<ObjectPair<String,String>> getPreferredDeliveryMechanisms()
879 {
880 return preferredDeliveryMechanisms;
881 }
882
883
884
885 /**
886 * Indicates whether to attempt to generate and deliver a token if the
887 * target user's password is expired.
888 *
889 * @return {@code true} if the server should attempt to deliver a token to a
890 * user with an expired password, or {@code false} if not.
891 */
892 public boolean deliverIfPasswordExpired()
893 {
894 return deliverIfPasswordExpired;
895 }
896
897
898
899 /**
900 * Indicates whether to attempt to generate and deliver a token if the
901 * target user's account is locked for some reason (e.g., because there have
902 * been too many failed authentication attempts, because the account has been
903 * idle for too long, or because the password was not changed soon enough
904 * after an administrative reset).
905 *
906 * @return {@code true} if the server should attempt to deliver a token to a
907 * user with a locked account, or {@code false} if not.
908 */
909 public boolean deliverIfAccountLocked()
910 {
911 return deliverIfAccountLocked;
912 }
913
914
915
916 /**
917 * Indicates whether to attempt to generate and deliver a token if the
918 * target user's account has been disabled by an administrator.
919 *
920 * @return {@code true} if the server should attempt to deliver a token to a
921 * user with a disabled account, or {@code false} if not.
922 */
923 public boolean deliverIfAccountDisabled()
924 {
925 return deliverIfAccountDisabled;
926 }
927
928
929
930 /**
931 * Indicates whether to attempt to generate and deliver a token if the
932 * target user's account has expired.
933 *
934 * @return {@code true} if the server should attempt to deliver a token to a
935 * user with an expired account, or {@code false} if not.
936 */
937 public boolean deliverIfAccountExpired()
938 {
939 return deliverIfAccountExpired;
940 }
941
942
943
944 /**
945 * {@inheritDoc}
946 */
947 @Override()
948 public DeliverSingleUseTokenExtendedResult process(
949 final LDAPConnection connection, final int depth)
950 throws LDAPException
951 {
952 final ExtendedResult extendedResponse = super.process(connection, depth);
953 return new DeliverSingleUseTokenExtendedResult(extendedResponse);
954 }
955
956
957
958 /**
959 * {@inheritDoc}.
960 */
961 @Override()
962 public DeliverSingleUseTokenExtendedRequest duplicate()
963 {
964 return duplicate(getControls());
965 }
966
967
968
969 /**
970 * {@inheritDoc}.
971 */
972 @Override()
973 public DeliverSingleUseTokenExtendedRequest duplicate(
974 final Control[] controls)
975 {
976 final DeliverSingleUseTokenExtendedRequest r =
977 new DeliverSingleUseTokenExtendedRequest(userDN, tokenID,
978 validityDurationMillis, messageSubject, fullTextBeforeToken,
979 fullTextAfterToken, compactTextBeforeToken, compactTextAfterToken,
980 preferredDeliveryMechanisms, deliverIfPasswordExpired,
981 deliverIfAccountLocked, deliverIfAccountDisabled,
982 deliverIfAccountExpired, controls);
983 r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
984 return r;
985 }
986
987
988
989 /**
990 * {@inheritDoc}
991 */
992 @Override()
993 public String getExtendedRequestName()
994 {
995 return INFO_EXTENDED_REQUEST_NAME_DELIVER_SINGLE_USE_TOKEN.get();
996 }
997
998
999
1000 /**
1001 * {@inheritDoc}
1002 */
1003 @Override()
1004 public void toString(final StringBuilder buffer)
1005 {
1006 buffer.append("DeliverSingleUseTokenExtendedRequest(userDN='");
1007 buffer.append(userDN);
1008 buffer.append("', tokenID='");
1009 buffer.append(tokenID);
1010 buffer.append('\'');
1011
1012 if (validityDurationMillis != null)
1013 {
1014 buffer.append(", validityDurationMillis=");
1015 buffer.append(validityDurationMillis);
1016 }
1017
1018 if (messageSubject != null)
1019 {
1020 buffer.append(", messageSubject='");
1021 buffer.append(messageSubject);
1022 buffer.append('\'');
1023 }
1024
1025 if (fullTextBeforeToken != null)
1026 {
1027 buffer.append(", fullTextBeforeToken='");
1028 buffer.append(fullTextBeforeToken);
1029 buffer.append('\'');
1030 }
1031
1032 if (fullTextAfterToken != null)
1033 {
1034 buffer.append(", fullTextAfterToken='");
1035 buffer.append(fullTextAfterToken);
1036 buffer.append('\'');
1037 }
1038
1039 if (compactTextBeforeToken != null)
1040 {
1041 buffer.append(", compactTextBeforeToken='");
1042 buffer.append(compactTextBeforeToken);
1043 buffer.append('\'');
1044 }
1045
1046 if (compactTextAfterToken != null)
1047 {
1048 buffer.append(", compactTextAfterToken='");
1049 buffer.append(compactTextAfterToken);
1050 buffer.append('\'');
1051 }
1052
1053 if (preferredDeliveryMechanisms != null)
1054 {
1055 buffer.append(", preferredDeliveryMechanisms={");
1056
1057 final Iterator<ObjectPair<String,String>> iterator =
1058 preferredDeliveryMechanisms.iterator();
1059 while (iterator.hasNext())
1060 {
1061 final ObjectPair<String,String> p = iterator.next();
1062 buffer.append('\'');
1063 buffer.append(p.getFirst());
1064 if (p.getSecond() != null)
1065 {
1066 buffer.append('(');
1067 buffer.append(p.getSecond());
1068 buffer.append(')');
1069 }
1070 buffer.append('\'');
1071 if (iterator.hasNext())
1072 {
1073 buffer.append(',');
1074 }
1075 }
1076 }
1077
1078 buffer.append(", deliverIfPasswordExpired=");
1079 buffer.append(deliverIfPasswordExpired);
1080 buffer.append(", deliverIfAccountLocked=");
1081 buffer.append(deliverIfAccountLocked);
1082 buffer.append(", deliverIfAccountDisabled=");
1083 buffer.append(deliverIfAccountDisabled);
1084 buffer.append(", deliverIfAccountExpired=");
1085 buffer.append(deliverIfAccountExpired);
1086
1087 final Control[] controls = getControls();
1088 if (controls.length > 0)
1089 {
1090 buffer.append(", controls={");
1091 for (int i=0; i < controls.length; i++)
1092 {
1093 if (i > 0)
1094 {
1095 buffer.append(", ");
1096 }
1097
1098 buffer.append(controls[i]);
1099 }
1100 buffer.append('}');
1101 }
1102
1103 buffer.append(')');
1104 }
1105 }