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