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.Collection; 027 import java.util.Collections; 028 import java.util.Iterator; 029 import java.util.List; 030 031 import com.unboundid.asn1.ASN1Boolean; 032 import com.unboundid.asn1.ASN1Element; 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.ExtendedResult; 037 import com.unboundid.ldap.sdk.LDAPException; 038 import com.unboundid.ldap.sdk.ResultCode; 039 import com.unboundid.util.Debug; 040 import com.unboundid.util.NotMutable; 041 import com.unboundid.util.StaticUtils; 042 import com.unboundid.util.ThreadSafety; 043 import com.unboundid.util.ThreadSafetyLevel; 044 045 import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*; 046 047 048 049 /** 050 * <BLOCKQUOTE> 051 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID 052 * LDAP SDK for Java. It is not available for use in applications that 053 * include only the Standard Edition of the LDAP SDK, and is not supported for 054 * use in conjunction with non-UnboundID products. 055 * </BLOCKQUOTE> 056 * This class provides an implementation of an extended result that may be used 057 * to provide information about which one-time password delivery mechanisms are 058 * supported for a user. 059 * <BR><BR> 060 * If the request was processed successfully, then the extended result will have 061 * an OID of 1.3.6.1.4.1.30221.2.6.48 and a value with the following encoding: 062 * <BR><BR> 063 * <PRE> 064 * GetSupportedOTPDeliveryMechanismsResult ::= SEQUENCE OF SEQUENCE { 065 * deliveryMechanism [0] OCTET STRING, 066 * isSupported [1] BOOLEAN OPTIONAL, 067 * recipientID [2] OCTET STRING OPTIONAL, 068 * ... } 069 * </PRE> 070 * 071 * @see GetSupportedOTPDeliveryMechanismsExtendedRequest 072 */ 073 @NotMutable() 074 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 075 public final class GetSupportedOTPDeliveryMechanismsExtendedResult 076 extends ExtendedResult 077 { 078 /** 079 * The OID (1.3.6.1.4.1.30221.2.6.48) for the get supported one-time password 080 * delivery mechanisms extended result. 081 */ 082 public static final String GET_SUPPORTED_OTP_DELIVERY_MECHANISMS_RESULT_OID = 083 "1.3.6.1.4.1.30221.2.6.48"; 084 085 086 087 /** 088 * The BER type for the delivery mechanism element. 089 */ 090 private static final byte TYPE_DELIVERY_MECHANISM = (byte) 0x80; 091 092 093 094 /** 095 * The BER type for the is supported element. 096 */ 097 private static final byte TYPE_IS_SUPPORTED = (byte) 0x81; 098 099 100 101 /** 102 * The BER type for the recipient ID element. 103 */ 104 private static final byte TYPE_RECIPIENT_ID = (byte) 0x82; 105 106 107 108 /** 109 * The serial version UID for this serializable class. 110 */ 111 private static final long serialVersionUID = -1811121368502797059L; 112 113 114 115 // The list of supported delivery mechanism information for this result. 116 private final List<SupportedOTPDeliveryMechanismInfo> deliveryMechanismInfo; 117 118 119 120 /** 121 * Decodes the provided extended result as a get supported OTP delivery 122 * mechanisms result. 123 * 124 * @param result The extended result to decode as a get supported OTP 125 * delivery mechanisms result. 126 * 127 * @throws LDAPException If the provided extended result cannot be decoded 128 * as a get supported OTP delivery mechanisms result. 129 */ 130 public GetSupportedOTPDeliveryMechanismsExtendedResult( 131 final ExtendedResult result) 132 throws LDAPException 133 { 134 super(result); 135 136 final ASN1OctetString value = result.getValue(); 137 if (value == null) 138 { 139 deliveryMechanismInfo = Collections.emptyList(); 140 } 141 else 142 { 143 try 144 { 145 final ASN1Element[] elements = 146 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 147 final ArrayList<SupportedOTPDeliveryMechanismInfo> mechInfo = 148 new ArrayList<SupportedOTPDeliveryMechanismInfo>(elements.length); 149 for (final ASN1Element e : elements) 150 { 151 final ASN1Element[] infoElements = 152 ASN1Sequence.decodeAsSequence(e).elements(); 153 final String name = ASN1OctetString.decodeAsOctetString( 154 infoElements[0]).stringValue(); 155 156 Boolean isSupported = null; 157 String recipientID = null; 158 for (int i=1; i < infoElements.length; i++) 159 { 160 switch (infoElements[i].getType()) 161 { 162 case TYPE_IS_SUPPORTED: 163 isSupported = ASN1Boolean.decodeAsBoolean( 164 infoElements[i]).booleanValue(); 165 break; 166 167 case TYPE_RECIPIENT_ID: 168 recipientID = ASN1OctetString.decodeAsOctetString( 169 infoElements[i]).stringValue(); 170 break; 171 172 default: 173 throw new LDAPException(ResultCode.DECODING_ERROR, 174 ERR_GET_SUPPORTED_OTP_MECH_RESULT_UNKNOWN_ELEMENT.get( 175 StaticUtils.toHex(infoElements[i].getType()))); 176 } 177 } 178 179 mechInfo.add(new SupportedOTPDeliveryMechanismInfo(name, isSupported, 180 recipientID)); 181 } 182 183 deliveryMechanismInfo = Collections.unmodifiableList(mechInfo); 184 } 185 catch (final LDAPException le) 186 { 187 Debug.debugException(le); 188 throw le; 189 } 190 catch (final Exception e) 191 { 192 Debug.debugException(e); 193 throw new LDAPException(ResultCode.DECODING_ERROR, 194 ERR_GET_SUPPORTED_OTP_MECH_RESULT_CANNOT_DECODE.get( 195 StaticUtils.getExceptionMessage(e)), 196 e); 197 } 198 } 199 } 200 201 202 203 /** 204 * Creates a new get supported OTP delivery mechanisms extended result object 205 * with the provided information. 206 * 207 * @param messageID The message ID for the LDAP message that is 208 * associated with this LDAP result. 209 * @param resultCode The result code from the response. It must 210 * not be {@code null}. 211 * @param diagnosticMessage The diagnostic message from the response, if 212 * available. 213 * @param matchedDN The matched DN from the response, if 214 * available. 215 * @param referralURLs The set of referral URLs from the response, 216 * if available. 217 * @param deliveryMechanismInfo The set of supported delivery mechanism info 218 * for the result, if appropriate. It should 219 * be {@code null} or empty for non-success 220 * results. 221 * @param controls The set of controls for the response. It 222 * may be {@code null} or empty if no controls 223 * are needed. 224 */ 225 public GetSupportedOTPDeliveryMechanismsExtendedResult(final int messageID, 226 final ResultCode resultCode, final String diagnosticMessage, 227 final String matchedDN, final String[] referralURLs, 228 final Collection<SupportedOTPDeliveryMechanismInfo> 229 deliveryMechanismInfo, 230 final Control... controls) 231 { 232 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs, 233 (resultCode == ResultCode.SUCCESS ? 234 GET_SUPPORTED_OTP_DELIVERY_MECHANISMS_RESULT_OID : null), 235 encodeValue(resultCode, deliveryMechanismInfo), controls); 236 237 if ((deliveryMechanismInfo == null) || deliveryMechanismInfo.isEmpty()) 238 { 239 this.deliveryMechanismInfo = Collections.emptyList(); 240 } 241 else 242 { 243 this.deliveryMechanismInfo = Collections.unmodifiableList( 244 new ArrayList<SupportedOTPDeliveryMechanismInfo>( 245 deliveryMechanismInfo)); 246 } 247 } 248 249 250 251 /** 252 * Encodes the provided information into an appropriate format for the value 253 * of this extended operation. 254 * 255 * @param resultCode The result code from the response. It must 256 * not be {@code null}. 257 * @param deliveryMechanismInfo The set of supported delivery mechanism info 258 * for the result, if appropriate. It should 259 * be {@code null} or empty for non-success 260 * results. 261 * 262 * @return The ASN.1 octet string containing the encoded value. 263 */ 264 private static ASN1OctetString encodeValue(final ResultCode resultCode, 265 final Collection<SupportedOTPDeliveryMechanismInfo> 266 deliveryMechanismInfo) 267 268 { 269 if (resultCode != ResultCode.SUCCESS) 270 { 271 return null; 272 } 273 274 if ((deliveryMechanismInfo == null) || deliveryMechanismInfo.isEmpty()) 275 { 276 return new ASN1OctetString(new ASN1Sequence().encode()); 277 } 278 279 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>( 280 deliveryMechanismInfo.size()); 281 for (final SupportedOTPDeliveryMechanismInfo i : deliveryMechanismInfo) 282 { 283 final ArrayList<ASN1Element> infoElements = new ArrayList<ASN1Element>(3); 284 infoElements.add(new ASN1OctetString(TYPE_DELIVERY_MECHANISM, 285 i.getDeliveryMechanism())); 286 287 if (i.isSupported() != null) 288 { 289 infoElements.add(new ASN1Boolean(TYPE_IS_SUPPORTED, i.isSupported())); 290 } 291 292 if (i.getRecipientID() != null) 293 { 294 infoElements.add(new ASN1OctetString(TYPE_RECIPIENT_ID, 295 i.getRecipientID())); 296 } 297 298 elements.add(new ASN1Sequence(infoElements)); 299 } 300 301 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 302 } 303 304 305 306 /** 307 * Retrieves a list containing information about the OTP delivery mechanisms 308 * supported by the server and which are available for use by the target user, 309 * if available. Note that it is possible for the same OTP delivery mechanism 310 * to appear in the list multiple times if that mechanism is supported for the 311 * user with multiple recipient IDs (e.g., if the server provides an "Email" 312 * delivery mechanism and a user has multiple email addresses, then the list 313 * may include a separate "Email" delivery mechanism info object for each 314 * of the user's email addresses). 315 * 316 * @return A list containing information about the OTP delivery mechanisms 317 * supported by the server and which are available for the target 318 * user, or an empty list if the server doesn't support any OTP 319 * delivery mechanisms or if the request was not processed 320 * successfully. 321 */ 322 public List<SupportedOTPDeliveryMechanismInfo> getDeliveryMechanismInfo() 323 { 324 return deliveryMechanismInfo; 325 } 326 327 328 329 /** 330 * {@inheritDoc} 331 */ 332 @Override() 333 public String getExtendedResultName() 334 { 335 return INFO_GET_SUPPORTED_OTP_MECH_RES_NAME.get(); 336 } 337 338 339 340 /** 341 * Appends a string representation of this extended result to the provided 342 * buffer. 343 * 344 * @param buffer The buffer to which a string representation of this 345 * extended result will be appended. 346 */ 347 @Override() 348 public void toString(final StringBuilder buffer) 349 { 350 buffer.append("GetSupportedOTPDeliveryMechanismsExtendedResult(" + 351 "resultCode="); 352 buffer.append(getResultCode()); 353 354 final int messageID = getMessageID(); 355 if (messageID >= 0) 356 { 357 buffer.append(", messageID="); 358 buffer.append(messageID); 359 } 360 361 buffer.append("mechanismInfo={"); 362 final Iterator<SupportedOTPDeliveryMechanismInfo> mechIterator = 363 deliveryMechanismInfo.iterator(); 364 while (mechIterator.hasNext()) 365 { 366 mechIterator.next().toString(buffer); 367 if (mechIterator.hasNext()) 368 { 369 buffer.append(", "); 370 } 371 } 372 buffer.append('}'); 373 374 final String diagnosticMessage = getDiagnosticMessage(); 375 if (diagnosticMessage != null) 376 { 377 buffer.append(", diagnosticMessage='"); 378 buffer.append(diagnosticMessage); 379 buffer.append('\''); 380 } 381 382 final String matchedDN = getMatchedDN(); 383 if (matchedDN != null) 384 { 385 buffer.append(", matchedDN='"); 386 buffer.append(matchedDN); 387 buffer.append('\''); 388 } 389 390 final String[] referralURLs = getReferralURLs(); 391 if (referralURLs.length > 0) 392 { 393 buffer.append(", referralURLs={"); 394 for (int i=0; i < referralURLs.length; i++) 395 { 396 if (i > 0) 397 { 398 buffer.append(", "); 399 } 400 401 buffer.append('\''); 402 buffer.append(referralURLs[i]); 403 buffer.append('\''); 404 } 405 buffer.append('}'); 406 } 407 408 final Control[] responseControls = getResponseControls(); 409 if (responseControls.length > 0) 410 { 411 buffer.append(", responseControls={"); 412 for (int i=0; i < responseControls.length; i++) 413 { 414 if (i > 0) 415 { 416 buffer.append(", "); 417 } 418 419 buffer.append(responseControls[i]); 420 } 421 buffer.append('}'); 422 } 423 424 buffer.append(')'); 425 } 426 }