001/* 002 * Copyright 2013-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2013-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; 041 042import com.unboundid.asn1.ASN1Element; 043import com.unboundid.asn1.ASN1OctetString; 044import com.unboundid.asn1.ASN1Sequence; 045import com.unboundid.ldap.sdk.Control; 046import com.unboundid.ldap.sdk.ExtendedResult; 047import com.unboundid.ldap.sdk.LDAPException; 048import com.unboundid.ldap.sdk.ResultCode; 049import com.unboundid.util.Debug; 050import com.unboundid.util.NotMutable; 051import com.unboundid.util.StaticUtils; 052import com.unboundid.util.ThreadSafety; 053import com.unboundid.util.ThreadSafetyLevel; 054import com.unboundid.util.Validator; 055 056import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*; 057 058 059 060/** 061 * This class provides an implementation of an extended result that may be used 062 * to provide information about the result of processing for a deliver one-time 063 * password extended request. If the one-time password was delivered 064 * successfully, then this result will include information about the mechanism 065 * through which that message was delivered. 066 * <BR> 067 * <BLOCKQUOTE> 068 * <B>NOTE:</B> This class, and other classes within the 069 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 070 * supported for use against Ping Identity, UnboundID, and 071 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 072 * for proprietary functionality or for external specifications that are not 073 * considered stable or mature enough to be guaranteed to work in an 074 * interoperable way with other types of LDAP servers. 075 * </BLOCKQUOTE> 076 * <BR> 077 * If the request was processed successfully, then the extended result will have 078 * an OID of 1.3.6.1.4.1.30221.2.6.25 and a value with the following encoding: 079 * <BR><BR> 080 * <PRE> 081 * DeliverOTPResult ::= SEQUENCE { 082 * deliveryMechanism [0] OCTET STRING, 083 * recipientDN [1] LDAPDN, 084 * recipientID [2] OCTET STRING OPTIONAL, 085 * message [3] OCTET STRING OPTIONAL, 086 * ... } 087 * </PRE> 088 * 089 * @see com.unboundid.ldap.sdk.unboundidds.UnboundIDDeliveredOTPBindRequest 090 * @see DeliverOneTimePasswordExtendedRequest 091 */ 092@NotMutable() 093@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 094public final class DeliverOneTimePasswordExtendedResult 095 extends ExtendedResult 096{ 097 /** 098 * The OID (1.3.6.1.4.1.30221.2.6.25) for the deliver one-time password 099 * extended result. 100 */ 101 public static final String DELIVER_OTP_RESULT_OID = 102 "1.3.6.1.4.1.30221.2.6.25"; 103 104 105 106 /** 107 * The BER type for the delivery mechanism element. 108 */ 109 private static final byte TYPE_MECH = (byte) 0x80; 110 111 112 113 /** 114 * The BER type for the recipient DN element. 115 */ 116 private static final byte TYPE_RECIPIENT_DN = (byte) 0x81; 117 118 119 120 /** 121 * The BER type for the recipient ID element. 122 */ 123 private static final byte TYPE_RECIPIENT_ID = (byte) 0x82; 124 125 126 127 /** 128 * The BER type for the delivery message element. 129 */ 130 private static final byte TYPE_MESSAGE = (byte) 0x83; 131 132 133 134 /** 135 * The serial version UID for this serializable class. 136 */ 137 private static final long serialVersionUID = 5077693879184160485L; 138 139 140 141 // The name of the mechanism by which the one-time password was delivered. 142 private final String deliveryMechanism; 143 144 // An message providing additional information about the delivery of the 145 // one-time password. 146 private final String deliveryMessage; 147 148 // An the DN of the user to whom the one-time password was sent. 149 private final String recipientDN; 150 151 // An identifier for the recipient of the one-time password. 152 private final String recipientID; 153 154 155 156 /** 157 * Creates a new deliver one-time password extended result from the provided 158 * generic extended result. 159 * 160 * @param extendedResult The generic extended result to be parsed as a 161 * deliver one-time password result. 162 * 163 * @throws LDAPException If the provided extended result cannot be parsed as 164 * a deliver one-time password result. 165 */ 166 public DeliverOneTimePasswordExtendedResult( 167 final ExtendedResult extendedResult) 168 throws LDAPException 169 { 170 super(extendedResult); 171 172 final ASN1OctetString value = extendedResult.getValue(); 173 if (value == null) 174 { 175 deliveryMechanism = null; 176 recipientDN = null; 177 recipientID = null; 178 deliveryMessage = null; 179 return; 180 } 181 182 String mech = null; 183 String dn = null; 184 String id = null; 185 String message = null; 186 try 187 { 188 for (final ASN1Element e : 189 ASN1Sequence.decodeAsSequence(value.getValue()).elements()) 190 { 191 switch (e.getType()) 192 { 193 case TYPE_MECH: 194 mech = ASN1OctetString.decodeAsOctetString(e).stringValue(); 195 break; 196 case TYPE_RECIPIENT_DN: 197 dn = ASN1OctetString.decodeAsOctetString(e).stringValue(); 198 break; 199 case TYPE_RECIPIENT_ID: 200 id = ASN1OctetString.decodeAsOctetString(e).stringValue(); 201 break; 202 case TYPE_MESSAGE: 203 message = ASN1OctetString.decodeAsOctetString(e).stringValue(); 204 break; 205 default: 206 throw new LDAPException(ResultCode.DECODING_ERROR, 207 ERR_DELIVER_OTP_RES_UNEXPECTED_ELEMENT_TYPE.get( 208 StaticUtils.toHex(e.getType()))); 209 } 210 } 211 } 212 catch (final LDAPException le) 213 { 214 Debug.debugException(le); 215 throw le; 216 } 217 catch (final Exception e) 218 { 219 Debug.debugException(e); 220 throw new LDAPException(ResultCode.DECODING_ERROR, 221 ERR_DELIVER_OTP_RES_ERROR_PARSING_VALUE.get( 222 StaticUtils.getExceptionMessage(e)), 223 e); 224 } 225 226 227 if (mech == null) 228 { 229 throw new LDAPException(ResultCode.DECODING_ERROR, 230 ERR_DELIVER_OTP_RES_NO_MECH.get()); 231 } 232 else 233 { 234 deliveryMechanism = mech; 235 } 236 237 if (dn == null) 238 { 239 throw new LDAPException(ResultCode.DECODING_ERROR, 240 ERR_DELIVER_OTP_RES_NO_RECIPIENT_DN.get()); 241 } 242 else 243 { 244 recipientDN = dn; 245 } 246 247 recipientID = id; 248 deliveryMessage = message; 249 } 250 251 252 253 /** 254 * Creates a new deliver one-time password extended result with the provided 255 * information. 256 * 257 * @param messageID The message ID for the LDAP message that is 258 * associated with this LDAP result. 259 * @param resultCode The result code from the response. 260 * @param diagnosticMessage The diagnostic message from the response, if 261 * available. 262 * @param matchedDN The matched DN from the response, if available. 263 * @param referralURLs The set of referral URLs from the response, if 264 * available. 265 * @param deliveryMechanism The name of the mechanism by which the one-time 266 * password was delivered, if available. This 267 * should be non-{@code null} for a success result. 268 * @param recipientDN The DN of the user to whom the one-time password 269 * was sent. This should be non-{@code null} for a 270 * success result. 271 * @param recipientID An identifier for the user to whom the one-time 272 * password was delivered. It may be {@code null} 273 * if no password was delivered or there is no 274 * appropriate identifier, but if a value is 275 * provided then it should appropriate for the 276 * delivery mechanism (e.g., the user's e-mail 277 * address if delivered via e-mail, a phone number 278 * if delivered via SMS or voice call, etc.). 279 * @param deliveryMessage A message providing additional information about 280 * the one-time password delivery, if available. 281 * If this is non-{@code null}, then the delivery 282 * mechanism must also be non-null. 283 * @param responseControls The set of controls from the response, if 284 * available. 285 */ 286 public DeliverOneTimePasswordExtendedResult(final int messageID, 287 final ResultCode resultCode, final String diagnosticMessage, 288 final String matchedDN, final String[] referralURLs, 289 final String deliveryMechanism, final String recipientDN, 290 final String recipientID, final String deliveryMessage, 291 final Control... responseControls) 292 { 293 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs, 294 ((deliveryMechanism == null) ? null : DELIVER_OTP_RESULT_OID), 295 encodeValue(deliveryMechanism, recipientDN, recipientID, 296 deliveryMessage), 297 responseControls); 298 299 this.deliveryMechanism = deliveryMechanism; 300 this.recipientDN = recipientDN; 301 this.recipientID = recipientID; 302 this.deliveryMessage = deliveryMessage; 303 } 304 305 306 307 /** 308 * Encodes the provided information into an ASN.1 octet string suitable for 309 * use as the value of this extended result. 310 * 311 * @param deliveryMechanism The name of the mechanism by which the one-time 312 * password was delivered, if available. This 313 * should be non-{@code null} for a success result. 314 * @param recipientDN The DN of the user to whom the one-time password 315 * was sent. This should be non-{@code null} for a 316 * success result. 317 * @param recipientID An identifier for the user to whom the one-time 318 * password was delivered. It may be {@code null} 319 * if no password was delivered or there is no 320 * appropriate identifier, but if a value is 321 * provided then it should appropriate for the 322 * delivery mechanism (e.g., the user's e-mail 323 * address if delivered via e-mail, a phone number 324 * if delivered via SMS or voice call, etc.). 325 * @param deliveryMessage A message providing additional information about 326 * the one-time password delivery, if available. 327 * If this is non-{@code null}, then the delivery 328 * mechanism must also be non-null. 329 * 330 * @return An ASN.1 octet string containing the encoded value, or 331 * {@code null} if the extended result should not have a value. 332 */ 333 private static ASN1OctetString encodeValue(final String deliveryMechanism, 334 final String recipientDN, 335 final String recipientID, 336 final String deliveryMessage) 337 { 338 if (deliveryMechanism == null) 339 { 340 Validator.ensureTrue((recipientID == null), 341 "The delivery mechanism must be non-null if the recipient ID " + 342 "is non-null."); 343 Validator.ensureTrue((deliveryMessage == null), 344 "The delivery mechanism must be non-null if the delivery message " + 345 "is non-null."); 346 return null; 347 } 348 349 Validator.ensureTrue((recipientDN != null), 350 "If a delivery mechanism is provided, then a recipient DN must also " + 351 "be provided."); 352 353 final ArrayList<ASN1Element> elements = new ArrayList<>(4); 354 elements.add(new ASN1OctetString(TYPE_MECH, deliveryMechanism)); 355 elements.add(new ASN1OctetString(TYPE_RECIPIENT_DN, recipientDN)); 356 357 if (recipientID != null) 358 { 359 elements.add(new ASN1OctetString(TYPE_RECIPIENT_ID, recipientID)); 360 } 361 362 if (deliveryMessage != null) 363 { 364 elements.add(new ASN1OctetString(TYPE_MESSAGE, deliveryMessage)); 365 } 366 367 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 368 } 369 370 371 372 /** 373 * Retrieves the name of the mechanism by which the one-time password was 374 * delivered to the end user, if available. 375 * 376 * @return The name of the mechanism by which the one-time password was 377 * delivered to the end user, or {@code null} if this is not 378 * available. 379 */ 380 public String getDeliveryMechanism() 381 { 382 return deliveryMechanism; 383 } 384 385 386 387 /** 388 * Retrieves the DN of the user to whom the one-time password was delivered, 389 * if available. 390 * 391 * @return The DN of the user to whom the one-time password was delivered, or 392 * {@code null} if this is not available. 393 */ 394 public String getRecipientDN() 395 { 396 return recipientDN; 397 } 398 399 400 401 /** 402 * Retrieves an identifier for the user to whom the one-time password was 403 * delivered, if available. If a recipient ID is provided, then it should be 404 * in a form appropriate to the delivery mechanism (e.g., an e-mail address 405 * if the password was delivered by e-mail, a phone number if it was delivered 406 * by SMS or a voice call, etc.). 407 * 408 * @return An identifier for the user to whom the one-time password was 409 * delivered, or {@code null} if this is not available. 410 */ 411 public String getRecipientID() 412 { 413 return recipientID; 414 } 415 416 417 418 /** 419 * Retrieves a message providing additional information about the one-time 420 * password delivery, if available. 421 * 422 * @return A message providing additional information about the one-time 423 * password delivery, or {@code null} if this is not available. 424 */ 425 public String getDeliveryMessage() 426 { 427 return deliveryMessage; 428 } 429 430 431 432 /** 433 * {@inheritDoc} 434 */ 435 @Override() 436 public String getExtendedResultName() 437 { 438 return INFO_DELIVER_OTP_RES_NAME.get(); 439 } 440 441 442 443 /** 444 * Appends a string representation of this extended result to the provided 445 * buffer. 446 * 447 * @param buffer The buffer to which a string representation of this 448 * extended result will be appended. 449 */ 450 @Override() 451 public void toString(final StringBuilder buffer) 452 { 453 buffer.append("DeliverOneTimePasswordExtendedResult(resultCode="); 454 buffer.append(getResultCode()); 455 456 final int messageID = getMessageID(); 457 if (messageID >= 0) 458 { 459 buffer.append(", messageID="); 460 buffer.append(messageID); 461 } 462 463 if (deliveryMechanism != null) 464 { 465 buffer.append(", deliveryMechanism='"); 466 buffer.append(deliveryMechanism); 467 buffer.append('\''); 468 } 469 470 if (recipientDN != null) 471 { 472 buffer.append(", recipientDN='"); 473 buffer.append(recipientDN); 474 buffer.append('\''); 475 } 476 477 if (recipientID != null) 478 { 479 buffer.append(", recipientID='"); 480 buffer.append(recipientID); 481 buffer.append('\''); 482 } 483 484 if (deliveryMessage != null) 485 { 486 buffer.append(", deliveryMessage='"); 487 buffer.append(deliveryMessage); 488 buffer.append('\''); 489 } 490 491 final String diagnosticMessage = getDiagnosticMessage(); 492 if (diagnosticMessage != null) 493 { 494 buffer.append(", diagnosticMessage='"); 495 buffer.append(diagnosticMessage); 496 buffer.append('\''); 497 } 498 499 final String matchedDN = getMatchedDN(); 500 if (matchedDN != null) 501 { 502 buffer.append(", matchedDN='"); 503 buffer.append(matchedDN); 504 buffer.append('\''); 505 } 506 507 final String[] referralURLs = getReferralURLs(); 508 if (referralURLs.length > 0) 509 { 510 buffer.append(", referralURLs={"); 511 for (int i=0; i < referralURLs.length; i++) 512 { 513 if (i > 0) 514 { 515 buffer.append(", "); 516 } 517 518 buffer.append('\''); 519 buffer.append(referralURLs[i]); 520 buffer.append('\''); 521 } 522 buffer.append('}'); 523 } 524 525 final Control[] responseControls = getResponseControls(); 526 if (responseControls.length > 0) 527 { 528 buffer.append(", responseControls={"); 529 for (int i=0; i < responseControls.length; i++) 530 { 531 if (i > 0) 532 { 533 buffer.append(", "); 534 } 535 536 buffer.append(responseControls[i]); 537 } 538 buffer.append('}'); 539 } 540 541 buffer.append(')'); 542 } 543}