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 }