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 *      Portions Copyright 2013-2024 Ping Identity Corporation
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.  The
247   *                         exception should have a result code of
248   *                         {@code TOKEN_DELIVERY_INVALID_RECIPIENT_ID} if the
249   *                         client specified a recipient ID that is not valid
250   *                         for the target user,
251   *                         {@code TOKEN_DELIVERY_MECHANISM_UNAVAILABLE} if
252   *                         this delivery mechanism is not supported for the
253   *                         target user, or
254   *                         {@code TOKEN_DELIVERY_ATTEMPT_FAILED} if the
255   *                         delivery mechanism should be supported but the
256   *                         attempt to deliver the one-time password failed.
257   */
258  public abstract String deliverOneTimePassword(final String oneTimePassword,
259                              final Entry userEntry,
260                              final String targetRecipientID,
261                              final StringBuilder resultMessage)
262         throws LDAPException;
263
264
265
266  /**
267   * Indicates whether this one-time password delivery mechanism supports
268   * general purpose message delivery via the {@link #deliverMessage} method.
269   *
270   * @return  {@code true} if the {@code deliverMessage} method can be used for
271   *          general-purpose message delivery, or {@code false} if only the
272   *          {@code deliverOneTimePassword} method can be used.
273   */
274  public boolean supportsGenericMessageDelivery()
275  {
276    return false;
277  }
278
279
280
281  /**
282   * Attempts to deliver a message (containing a single-use token) to the
283   * specified user.
284   *
285   * @param  config              The general configuration for this OTP delivery
286   *                             mechanism.
287   * @param  tokenID             The token ID for the single-use token contained
288   *                             in the message to be delivered.
289   * @param  tokenValue          The value for the single-use token contained
290   *                             in the message to be delivered.
291   * @param  messageSubject      The message subject that should be used, if
292   *                             appropriate.  It may be {@code null} if no
293   *                             subject was provided.
294   * @param  fullMessage         The message that should be delivered if this
295   *                             delivery mechanism does not impose a
296   *                             significant constraint on message size.
297   * @param  compactMessage      The message that should be delivered if this
298   *                             delivery mechanism does impose a significant
299   *                             constraint on message size.
300   * @param  userEntry           The entry for the user to whom the token should
301   *                             be delivered.
302   * @param  targetRecipientID   The target recipient ID that should be used for
303   *                             the delivery, if possible.  It may be
304   *                             {@code null} if there is no appropriate
305   *                             identifier for this delivery mechanism or if
306   *                             the delivery mechanism may choose which
307   *                             recipient ID should be used.  However, if it is
308   *                             non-{@code null}, then the delivery mechanism
309   *                             must verify that the provided recipient ID is
310   *                             valid for the associated user (e.g., for an
311   *                             e-mail delivery mechanism, the recipient ID
312   *                             would probably be an e-mail address, and the
313   *                             delivery mechanism must verify that the
314   *                             provided e-mail address is associated with the
315   *                             given user account).
316   * @param  resultMessage       A buffer to which a message may be appended
317   *                             with additional information about the token
318   *                             delivery.
319   *
320   * @return  An identifier for the user in a format appropriate to the delivery
321   *          mechanism (e.g., an e-mail address for an e-mail delivery
322   *          mechanism, a phone number for an SMS or voice call delivery
323   *          mechanism, etc.).  It may be {@code null} if there is no
324   *          appropriate identifier for this delivery mechanism that is needed
325   *          beyond the name of the delivery mechanism and the DN of the
326   *          recipient.
327   *
328   * @throws  LDAPException  If a problem is encountered while attempting to
329   *                         deliver the single-use token message to the user.
330   *                         The exception should have a result code of
331   *                         {@code TOKEN_DELIVERY_INVALID_RECIPIENT_ID} if the
332   *                         client specified a recipient ID that is not valid
333   *                         for the target user,
334   *                         {@code TOKEN_DELIVERY_MECHANISM_UNAVAILABLE} if
335   *                         this delivery mechanism is not supported for the
336   *                         target user, or
337   *                         {@code TOKEN_DELIVERY_ATTEMPT_FAILED} if the
338   *                         delivery mechanism should be supported but the
339   *                         attempt to deliver the token failed.
340   */
341  public String deliverMessage(
342                     final OneTimePasswordDeliveryMechanismConfig config,
343                     final String tokenID, final String tokenValue,
344                     final String messageSubject, final String fullMessage,
345                     final String compactMessage, final Entry userEntry,
346                     final String targetRecipientID,
347                     final StringBuilder resultMessage)
348         throws LDAPException
349  {
350    throw new LDAPException(ResultCode.OTHER,
351         "The '" + config.getConfigObjectName() + "' OTP delivery mechanism " +
352              "does not support arbitrary message delivery.");
353  }
354
355
356
357  /**
358   * Updates the provided list with one or more
359   * {@code SupportedOTPDeliveryMechanismInfo} objects indicating whether this
360   * OTP delivery mechanism is supported for the specified user.
361   *
362   * @param  config                 The general configuration for this OTP
363   *                                delivery mechanism.
364   * @param  userEntry              The entry of the user for whom to make the
365   *                                determination.
366   * @param  deliveryMechanismInfo  The list to which any objects may be
367   *                                appended with information about the level
368   *                                of support this OTP delivery mechanism has
369   *                                for use in conjunction with the specified
370   *                                user.
371   */
372  public void getSupportedDeliveryMechanismInfo(
373       final OneTimePasswordDeliveryMechanismConfig config,
374       final Entry userEntry,
375       final List<SupportedOTPDeliveryMechanismInfo> deliveryMechanismInfo)
376  {
377    deliveryMechanismInfo.add(
378         new SupportedOTPDeliveryMechanismInfo(config.getConfigObjectName(),
379              null, null));
380  }
381
382
383
384  /**
385   * {@inheritDoc}
386   */
387  @Override()
388  public Map<List<String>,String> getExamplesArgumentSets()
389  {
390    return Collections.emptyMap();
391  }
392}