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 }