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