001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * docs/licenses/cddl.txt
011 * or http://www.opensource.org/licenses/cddl1.php.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * docs/licenses/cddl.txt.  If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 *      Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 *      Copyright 2013-2016 UnboundID Corp.
026 */
027package com.unboundid.directory.sdk.ds.api;
028
029
030
031import java.util.Collections;
032import java.util.List;
033import java.util.Map;
034
035import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
036import com.unboundid.directory.sdk.common.internal.Reconfigurable;
037import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
038import com.unboundid.directory.sdk.common.types.Entry;
039import com.unboundid.directory.sdk.ds.config.
040            OneTimePasswordDeliveryMechanismConfig;
041import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
042import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
043import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
044import com.unboundid.ldap.sdk.LDAPException;
045import com.unboundid.ldap.sdk.ResultCode;
046import com.unboundid.ldap.sdk.unboundidds.extensions.
047            SupportedOTPDeliveryMechanismInfo;
048import com.unboundid.util.Extensible;
049import com.unboundid.util.ThreadSafety;
050import com.unboundid.util.ThreadSafetyLevel;
051import com.unboundid.util.args.ArgumentException;
052import com.unboundid.util.args.ArgumentParser;
053
054
055
056/**
057 * This class defines an API that must be implemented by extensions which
058 * attempt to deliver one-time passwords (OTPs) to end users through some
059 * out-of-band mechanism.  The one-time passwords will have been generated by
060 * the deliver one-time password extended request, and may be used to
061 * authenticate to the server through the UNBOUNDID-DELIVERED-OTP SASL
062 * mechanism.
063 * <BR>
064 * <H2>Configuring One-Time Password Delivery Mechanisms</H2>
065 * In order to configure a one-time password delivery mechanism created using
066 * this API, use a command like:
067 * <PRE>
068 *      dsconfig create-otp-delivery-mechanism \
069 *           --mechanism-name "<I>{mechanism-name}</I>" \
070 *           --type third-party \
071 *           --set enabled:true \
072 *           --set "extension-class:<I>{class-name}</I>" \
073 *           --set "extension-argument:<I>{name=value}</I>"
074 * </PRE>
075 * where "<I>{mechanism-name}</I>" is the name to use for the one-time password
076 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java class
077 * that extends
078 * {@code com.unboundid.directory.sdk.ds.api.OneTimePasswordDeliveryMechanism},
079 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
080 * provide to the one-time password delivery mechanism.  If multiple arguments
081 * should be provided to the OTP delivery mechanism, then the
082 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
083 * provided multiple times.
084 */
085@Extensible()
086@DirectoryServerExtension()
087@DirectoryProxyServerExtension(appliesToLocalContent=true,
088     appliesToRemoteContent=true)
089@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
090public abstract class OneTimePasswordDeliveryMechanism
091       implements UnboundIDExtension,
092                  Reconfigurable<OneTimePasswordDeliveryMechanismConfig>,
093                  ExampleUsageProvider
094{
095  /**
096   * Creates a new instance of this one-time password delivery mechanism.  All
097   * OTP delivery mechanism implementations must include a default constructor,
098   * but any initialization should generally be done in the
099   * {@code initializeOTPDeliveryMechanism} method.
100   */
101  public OneTimePasswordDeliveryMechanism()
102  {
103    // No implementation is required.
104  }
105
106
107
108  /**
109   * {@inheritDoc}
110   */
111  @Override()
112  public abstract String getExtensionName();
113
114
115
116  /**
117   * {@inheritDoc}
118   */
119  @Override()
120  public abstract String[] getExtensionDescription();
121
122
123
124  /**
125   * {@inheritDoc}
126   */
127  @Override()
128  public void defineConfigArguments(final ArgumentParser parser)
129         throws ArgumentException
130  {
131    // No arguments will be allowed by default.
132  }
133
134
135
136  /**
137   * Initializes this one-time password delivery mechanism.
138   *
139   * @param  serverContext  A handle to the server context for the server in
140   *                        which this extension is running.
141   * @param  config         The general configuration for this OTP delivery
142   *                        mechanism.
143   * @param  parser         The argument parser which has been initialized from
144   *                        the configuration for this OTP delivery mechanism.
145   *
146   * @throws  LDAPException  If a problem occurs while initializing this OTP
147   *                         delivery mechanism.
148   */
149  public void initializeOTPDeliveryMechanism(
150                   final DirectoryServerContext serverContext,
151                   final OneTimePasswordDeliveryMechanismConfig config,
152                   final ArgumentParser parser)
153         throws LDAPException
154  {
155    // No initialization will be performed by default.
156  }
157
158
159
160  /**
161   * {@inheritDoc}
162   */
163  @Override()
164  public boolean isConfigurationAcceptable(
165                      final OneTimePasswordDeliveryMechanismConfig config,
166                      final ArgumentParser parser,
167                      final List<String> unacceptableReasons)
168  {
169    // No extended validation will be performed by default.
170    return true;
171  }
172
173
174
175  /**
176   * {@inheritDoc}
177   */
178  @Override()
179  public ResultCode applyConfiguration(
180                         final OneTimePasswordDeliveryMechanismConfig config,
181                         final ArgumentParser parser,
182                         final List<String> adminActionsRequired,
183                         final List<String> messages)
184  {
185    // By default, no configuration changes will be applied.  If there are any
186    // arguments, then add an admin action message indicating that the extension
187    // needs to be restarted for any changes to take effect.
188    if (! parser.getNamedArguments().isEmpty())
189    {
190      adminActionsRequired.add(
191           "No configuration change has actually been applied.  The new " +
192                "configuration will not take effect until this one-time " +
193                "password delivery mechanism is disabled and re-enabled or " +
194                "until the server is restarted.");
195    }
196
197    return ResultCode.SUCCESS;
198  }
199
200
201
202  /**
203   * Performs any cleanup which may be necessary when this one-time password
204   * delivery mechanism is to be taken out of service.
205   */
206  public void finalizeOTPDeliveryMechanism()
207  {
208    // No implementation is required.
209  }
210
211
212
213  /**
214   * Attempts to deliver the provided one-time password to the specified user.
215   *
216   * @param  oneTimePassword    The one-time password to be delivered.
217   * @param  userEntry          The entry for the user to whom the one-time
218   *                            password should be delivered.
219   * @param  targetRecipientID  The target recipient ID that should be used for
220   *                            the delivery, if possible.  It may be
221   *                            {@code null} if there is no appropriate
222   *                            identifier for this delivery mechanism or if
223   *                            the delivery mechanism may choose which
224   *                            recipient ID should be used.  However, if it is
225   *                            non-{@code null}, then the delivery mechanism
226   *                            must verify that the provided recipient ID is
227   *                            valid for the associated user (e.g., for an
228   *                            e-mail delivery mechanism, the recipient ID
229   *                            would probably be an e-mail address, and the
230   *                            delivery mechanism must verify that the provided
231   *                            e-mail address is associated with the given
232   *                            user account).
233   * @param  resultMessage      A buffer to which a message may be appended with
234   *                            additional information about the password
235   *                            delivery.
236   *
237   * @return  An identifier for the user in a format appropriate to the delivery
238   *          mechanism (e.g., an e-mail address for an e-mail delivery
239   *          mechanism, a phone number for an SMS or voice call delivery
240   *          mechanism, etc.).  It may be {@code null} if there is no
241   *          appropriate identifier for this delivery mechanism that is needed
242   *          beyond the name of the delivery mechanism and the DN of the
243   *          recipient.
244   *
245   * @throws  LDAPException  If a problem is encountered while attempting to
246   *                         send the one-time password to the user.
247   */
248  public abstract String deliverOneTimePassword(final String oneTimePassword,
249                              final Entry userEntry,
250                              final String targetRecipientID,
251                              final StringBuilder resultMessage)
252         throws LDAPException;
253
254
255
256  /**
257   * Indicates whether this one-time password delivery mechanism supports
258   * general purpose message delivery via the {@link #deliverMessage} method.
259   *
260   * @return  {@code true} if the {@code deliverMessage} method can be used for
261   *          general-purpose message delivery, or {@code false} if only the
262   *          {@code deliverOneTimePassword} method can be used.
263   */
264  public boolean supportsGenericMessageDelivery()
265  {
266    return false;
267  }
268
269
270
271  /**
272   * Attempts to deliver a message (containing a single-use token) to the
273   * specified user.
274   *
275   * @param  config              The general configuration for this OTP delivery
276   *                             mechanism.
277   * @param  tokenID             The token ID for the single-use token contained
278   *                             in the message to be delivered.
279   * @param  tokenValue          The value for the single-use token contained
280   *                             in the message to be delivered.
281   * @param  messageSubject      The message subject that should be used, if
282   *                             appropriate.  It may be {@code null} if no
283   *                             subject was provided.
284   * @param  fullMessage         The message that should be delivered if this
285   *                             delivery mechanism does not impose a
286   *                             significant constraint on message size.
287   * @param  compactMessage      The message that should be delivered if this
288   *                             delivery mechanism does impose a significant
289   *                             constraint on message size.
290   * @param  userEntry           The entry for the user to whom the token should
291   *                             be delivered.
292   * @param  targetRecipientID   The target recipient ID that should be used for
293   *                             the delivery, if possible.  It may be
294   *                             {@code null} if there is no appropriate
295   *                             identifier for this delivery mechanism or if
296   *                             the delivery mechanism may choose which
297   *                             recipient ID should be used.  However, if it is
298   *                             non-{@code null}, then the delivery mechanism
299   *                             must verify that the provided recipient ID is
300   *                             valid for the associated user (e.g., for an
301   *                             e-mail delivery mechanism, the recipient ID
302   *                             would probably be an e-mail address, and the
303   *                             delivery mechanism must verify that the
304   *                             provided e-mail address is associated with the
305   *                             given user account).
306   * @param  resultMessage       A buffer to which a message may be appended
307   *                             with additional information about the token
308   *                             delivery.
309   *
310   * @return  An identifier for the user in a format appropriate to the delivery
311   *          mechanism (e.g., an e-mail address for an e-mail delivery
312   *          mechanism, a phone number for an SMS or voice call delivery
313   *          mechanism, etc.).  It may be {@code null} if there is no
314   *          appropriate identifier for this delivery mechanism that is needed
315   *          beyond the name of the delivery mechanism and the DN of the
316   *          recipient.
317   *
318   * @throws  LDAPException  If a problem is encountered while attempting to
319   *                         deliver the single-use token message to the user.
320   */
321  public String deliverMessage(
322                     final OneTimePasswordDeliveryMechanismConfig config,
323                     final String tokenID, final String tokenValue,
324                     final String messageSubject, final String fullMessage,
325                     final String compactMessage, final Entry userEntry,
326                     final String targetRecipientID,
327                     final StringBuilder resultMessage)
328         throws LDAPException
329  {
330    throw new LDAPException(ResultCode.OTHER,
331         "The '" + config.getConfigObjectName() + "' OTP delivery mechanism " +
332              "does not support arbitrary message delivery.");
333  }
334
335
336
337  /**
338   * Updates the provided list with one or more
339   * {@code SupportedOTPDeliveryMechanismInfo} objects indicating whether this
340   * OTP delivery mechanism is supported for the specified user.
341   *
342   * @param  config                 The general configuration for this OTP
343   *                                delivery mechanism.
344   * @param  userEntry              The entry of the user for whom to make the
345   *                                determination.
346   * @param  deliveryMechanismInfo  The list to which any objects may be
347   *                                appended with information about the level
348   *                                of support this OTP delivery mechanism has
349   *                                for use in conjunction with the specified
350   *                                user.
351   */
352  public void getSupportedDeliveryMechanismInfo(
353       final OneTimePasswordDeliveryMechanismConfig config,
354       final Entry userEntry,
355       final List<SupportedOTPDeliveryMechanismInfo> deliveryMechanismInfo)
356  {
357    deliveryMechanismInfo.add(
358         new SupportedOTPDeliveryMechanismInfo(config.getConfigObjectName(),
359              null, null));
360  }
361
362
363
364  /**
365   * {@inheritDoc}
366   */
367  @Override()
368  public Map<List<String>,String> getExamplesArgumentSets()
369  {
370    return Collections.emptyMap();
371  }
372}