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 2012-2021 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.operation.SASLBindRequest;
039import com.unboundid.directory.sdk.common.types.Entry;
040import com.unboundid.directory.sdk.common.types.OperationContext;
041import com.unboundid.directory.sdk.ds.config.SASLMechanismHandlerConfig;
042import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
043import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
044import com.unboundid.directory.sdk.ds.types.SASLBindResult;
045import com.unboundid.directory.sdk.ds.types.SASLBindResultFactory;
046import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
047import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
048import com.unboundid.ldap.sdk.LDAPException;
049import com.unboundid.ldap.sdk.ResultCode;
050import com.unboundid.util.Extensible;
051import com.unboundid.util.ThreadSafety;
052import com.unboundid.util.ThreadSafetyLevel;
053import com.unboundid.util.args.ArgumentException;
054import com.unboundid.util.args.ArgumentParser;
055
056
057
058/**
059 * This class defines an API that must be implemented by extensions which add
060 * support for custom SASL mechanisms to the server, which can provide support
061 * for custom authentication (and optionally, authorization) methods.
062 * <BR>
063 * <H2>Configuring SASL Mechanism Handlers</H2>
064 * In order to configure a SASL mechanism handler created using this API, use a
065 * command like:
066 * <PRE>
067 *      dsconfig create-sasl-mechanism-handler \
068 *           --handler-name "<I>{handler-name}</I>" \
069 *           --type third-party \
070 *           --set enabled:true \
071 *           --set "extension-class:<I>{class-name}</I>" \
072 *           --set "extension-argument:<I>{name=value}</I>"
073 * </PRE>
074 * where "<I>{handler-name}</I>" is the name to use for the SASL mechanism
075 * handler instance, "<I>{class-name}</I>" is the fully-qualified name of the
076 * Java class that extends
077 * {@code com.unboundid.directory.sdk.ds.api.SASLMechanismHandler}, and
078 * "<I>{name=value}</I>" represents name-value pairs for any arguments to
079 * provide to the handler.  If multiple arguments should be provided to the SASL
080 * mechanism handler, then the
081 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
082 * provided multiple times.
083 */
084@Extensible()
085@DirectoryServerExtension()
086@DirectoryProxyServerExtension(appliesToLocalContent=true,
087     appliesToRemoteContent=true,
088     notes="Any SASL bind requests received by the Directory Proxy Server " +
089          "will be processed by the Directory Proxy Server itself rather " +
090          "than being forwarded to backend servers.  However, a SASL " +
091          "mechanism handler running in the Directory Proxy Server may " +
092          "perform internal operations which reference content in the " +
093          "backend servers as if it was contained locally in the server.")
094@SynchronizationServerExtension(appliesToLocalContent=true,
095     appliesToSynchronizedContent=false)
096@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
097public abstract class SASLMechanismHandler
098       implements UnboundIDExtension,
099                  Reconfigurable<SASLMechanismHandlerConfig>,
100                  ExampleUsageProvider
101{
102  /**
103   * Creates a new instance of this SASL mechanism handler.  All SASL
104   * mechanism handler implementations must include a default constructor, but
105   * any initialization
106   * should generally be done in the {@code initializeSASLMechanismHandler}
107   * method.
108   */
109  public SASLMechanismHandler()
110  {
111    // No implementation is required.
112  }
113
114
115
116  /**
117   * {@inheritDoc}
118   */
119  public abstract String getExtensionName();
120
121
122
123  /**
124   * {@inheritDoc}
125   */
126  public abstract String[] getExtensionDescription();
127
128
129
130  /**
131   * {@inheritDoc}
132   */
133  public void defineConfigArguments(final ArgumentParser parser)
134         throws ArgumentException
135  {
136    // No arguments will be allowed by default.
137  }
138
139
140
141  /**
142   * Initializes this SASL mechanism handler.
143   *
144   * @param  serverContext  A handle to the server context for the server in
145   *                        which this extension is running.
146   * @param  config         The general configuration for this SASL mechanism
147   *                        handler.
148   * @param  parser         The argument parser which has been initialized from
149   *                        the configuration for this SASL mechanism handler.
150   *
151   * @throws  LDAPException  If a problem occurs while initializing this SASL
152   *                         mechanism handler.
153   */
154  public void initializeSASLMechanismHandler(
155                   final DirectoryServerContext serverContext,
156                   final SASLMechanismHandlerConfig config,
157                   final ArgumentParser parser)
158         throws LDAPException
159  {
160    // No initialization will be performed by default.
161  }
162
163
164
165  /**
166   * {@inheritDoc}
167   */
168  public boolean isConfigurationAcceptable(
169                      final SASLMechanismHandlerConfig config,
170                      final ArgumentParser parser,
171                      final List<String> unacceptableReasons)
172  {
173    // No extended validation will be performed by default.
174    return true;
175  }
176
177
178
179  /**
180   * {@inheritDoc}
181   */
182  public ResultCode applyConfiguration(final SASLMechanismHandlerConfig config,
183                                       final ArgumentParser parser,
184                                       final List<String> adminActionsRequired,
185                                       final List<String> messages)
186  {
187    // By default, no configuration changes will be applied.  If there are any
188    // arguments, then add an admin action message indicating that the extension
189    // needs to be restarted for any changes to take effect.
190    if (! parser.getNamedArguments().isEmpty())
191    {
192      adminActionsRequired.add(
193           "No configuration change has actually been applied.  The new " +
194                "configuration will not take effect until this SASL " +
195                "mechanism handler is disabled and re-enabled or until the " +
196                "server is restarted.");
197    }
198
199    return ResultCode.SUCCESS;
200  }
201
202
203
204  /**
205   * Performs any cleanup which may be necessary when this SASL mechanism
206   * handler is to be taken out of service.
207   */
208  public void finalizeSASLMechanismHandler()
209  {
210    // No implementation is required.
211  }
212
213
214
215  /**
216   * Retrieves a list of the names of the SASL mechanisms supported by this
217   * SASL mechanism handler.  This method will be invoked only immediately after
218   * the {@link #initializeSASLMechanismHandler} method is called.
219   *
220   * @return  A list of the names of the SASL mechanisms supported by this SASL
221   *          mechanism handler.
222   */
223  public abstract List<String> getSASLMechanismNames();
224
225
226
227  /**
228   * Indicates whether the SASL authentication process using the specified
229   * mechanism may be considered secure (i.e., that a third party able to
230   * observe the communication, potentially over an insecure communication
231   * channel, would not be able to reproduce the authentication process).
232   *
233   * @param  mechanism  The name of the mechanism for which to make the
234   *                    determination.  This will only be invoked with names of
235   *                    mechanisms returned by the
236   *                    {@link #getSASLMechanismNames} method.
237   *
238   * @return  {@code true} if the specified SASL mechanism should be considered
239   *          secure, or {@code false} if not.
240   */
241  public abstract boolean isSecure(final String mechanism);
242
243
244
245  /**
246   * Indicates whether the SASL authentication process using the specified
247   * mechanism involves the use of a password stored locally in the server
248   * (optionally in combination with other forms of credentials).
249   *
250   * @param  mechanism  The name of the mechanism for which to make the
251   *                    determination.  This will only be invoked with names of
252   *                    mechanisms returned by the
253   *                    {@link #getSASLMechanismNames} method.
254   *
255   * @return  {@code true} if the specified SASL mechanism makes use of a local
256   *          password, or {@code false} if not.
257   */
258  public abstract boolean isPasswordBased(final String mechanism);
259
260
261
262  /**
263   * Performs the appropriate processing for the provided SASL bind request.
264   *
265   * @param  operationContext  The context for the bind operation.
266   * @param  bindRequest       The SASL bind request to be processed.
267   * @param  resultFactory     A factory object that will be used to construct
268   *                           the result to return.
269   *
270   * @return  An object with information about the result of the SASL bind
271   *          processing.
272   */
273  public abstract SASLBindResult processSASLBind(
274                       final OperationContext operationContext,
275                       final SASLBindRequest bindRequest,
276                       final SASLBindResultFactory resultFactory);
277
278
279
280  /**
281   * {@inheritDoc}
282   */
283  public Map<List<String>,String> getExamplesArgumentSets()
284  {
285    return Collections.emptyMap();
286  }
287
288
289
290  /**
291   * Indicates whether the specified SASL mechanism, which is listed as
292   * supported by this handler, is available for use by the given user.
293   *
294   * @param  mechanism          The name of the SASL mechanism for which to make
295   *                            the determination.  It will be one of the
296   *                            mechanisms for which this handler is registered.
297   * @param  passwordAttribute  The name of the attribute used to hold the
298   *                            password for the user.
299   * @param  userEntry          The entry for the user for whom to make the
300   *                            determination.
301   *
302   * @return  {@code true} if the SASL mechanism is supported for the user,
303   *          {@code false} if not, or {@code null} if it could not be
304   *          determined.
305   */
306  public Boolean isMechanismAvailableForUser(final String mechanism,
307                                             final String passwordAttribute,
308                                             final Entry userEntry)
309  {
310    // This should be overridden by subclasses that wish to implement this
311    // functionality.
312    return null;
313  }
314
315
316
317  /**
318   * Indicates whether the specified SASL mechanism may require multiple stages
319   * to process.
320   *
321   * @param  mechanism  The mechanism for which to make the determination.
322   *
323   * @return  {@code true} if the specified SASL mechanism may require multiple
324   *          stages to process, {@code false} if not, or {@code null} if the
325   *          answer is not known for the specified mechanism.
326   */
327  public Boolean isMultiStageMechanism(final String mechanism)
328  {
329    // This should be overridden by subclasses that wish to impelement this
330    // functionality.
331    return null;
332  }
333}