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