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 2021-2023 Ping Identity Corporation
026 */
027package com.unboundid.directory.sdk.ds.api;
028
029
030
031import java.util.Collections;
032import java.util.List;
033
034import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
035import com.unboundid.directory.sdk.common.internal.Reconfigurable;
036import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
037import com.unboundid.directory.sdk.common.operation.SimpleBindRequest;
038import com.unboundid.directory.sdk.common.types.Entry;
039import com.unboundid.directory.sdk.common.types.OperationContext;
040import com.unboundid.directory.sdk.ds.config.
041            PassThroughAuthenticationHandlerConfig;
042import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
043import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
044import com.unboundid.directory.sdk.ds.types.PassThroughAuthenticationResult;
045import com.unboundid.ldap.sdk.Attribute;
046import com.unboundid.ldap.sdk.LDAPException;
047import com.unboundid.ldap.sdk.ResultCode;
048import com.unboundid.util.Extensible;
049import com.unboundid.util.NotNull;
050import com.unboundid.util.Nullable;
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 that
060 * attempt to pass through authentication to an external service.
061 * <BR>
062 * <H2>Configuring Pass-Through Authentication Handlers</H2>
063 * In order to configure a pass-through authentication handler created using
064 * this API, use a command like:
065 * <PRE>
066 *      dsconfig create-pass-through-authentication-handler \
067 *           --handler-name "<I>{handler-name}</I>" \
068 *           --type third-party \
069 *           --set "extension-class:<I>{class-name}</I>" \
070 *           --set "extension-argument:<I>{name=value}</I>"
071 * </PRE>
072 * where "<I>{handler-name}</I>" is the name to use for the pass-through
073 * authentication handler instance, "<I>{class-name}</I>" is the fully-qualified
074 * name of the Java class that extends
075 * {@code com.unboundid.directory.sdk.ds.api.PassThroughAuthenticationHandler},
076 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
077 * provide to the handler.  If multiple arguments should be provided to the
078 * pass-through authentication handler, then the
079 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
080 * provided multiple times.
081 */
082@Extensible()
083@DirectoryServerExtension()
084@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
085public abstract class PassThroughAuthenticationHandler
086       implements UnboundIDExtension,
087                  Reconfigurable<PassThroughAuthenticationHandlerConfig>,
088                  ExampleUsageProvider
089{
090  /**
091   * Creates a new instance of this pass-through authentication handler.  All
092   * pass-through authentication handler implementations must include a default
093   * constructor, but any initialization
094   * should generally be done in the
095   * {@link #initializePassThroughAuthenticationHandler} method.
096   */
097  public PassThroughAuthenticationHandler()
098  {
099    // No implementation is required.
100  }
101
102
103
104  /**
105   * {@inheritDoc}
106   */
107  @Override()
108  @NotNull()
109  public abstract String getExtensionName();
110
111
112
113  /**
114   * {@inheritDoc}
115   */
116  @Override()
117  @Nullable()
118  public abstract String[] getExtensionDescription();
119
120
121
122  /**
123   * {@inheritDoc}
124   */
125  public void defineConfigArguments(@NotNull final ArgumentParser parser)
126         throws ArgumentException
127  {
128    // No arguments will be allowed by default.
129  }
130
131
132
133  /**
134   * Initializes this pass-through authentication handler.
135   *
136   * @param  serverContext  A handle to the server context for the server in
137   *                        which this extension is running.  It will not be
138   *                        {@code null}.
139   * @param  config         The general configuration for this pass-through
140   *                        authentication handler.  It will not be
141   *                        {@code null}.
142   * @param  parser         The argument parser which has been initialized from
143   *                        the configuration for this pass-through
144   *                        authentication handler.  It will not be
145   *                        {@code null}.
146   *
147   * @throws  LDAPException  If a problem occurs while initializing this
148   *                         pass-through authentication handler.
149   */
150  public void initializePassThroughAuthenticationHandler(
151                   @NotNull final DirectoryServerContext serverContext,
152                   @NotNull final PassThroughAuthenticationHandlerConfig config,
153                   @NotNull final ArgumentParser parser)
154         throws LDAPException
155  {
156    // No initialization will be performed by default.
157  }
158
159
160
161  /**
162   * {@inheritDoc}
163   */
164  @Override()
165  public boolean isConfigurationAcceptable(
166              @NotNull final PassThroughAuthenticationHandlerConfig config,
167              @NotNull final ArgumentParser parser,
168              @NotNull final List<String> unacceptableReasons)
169  {
170    // No extended validation will be performed by default.
171    return true;
172  }
173
174
175
176  /**
177   * {@inheritDoc}
178   */
179  @NotNull()
180  public ResultCode applyConfiguration(
181              @NotNull final PassThroughAuthenticationHandlerConfig config,
182              @NotNull final ArgumentParser parser,
183              @NotNull final List<String> adminActionsRequired,
184              @NotNull final List<String> messages)
185  {
186    // By default, no configuration changes will be applied.  If there are any
187    // arguments, then add an admin action message indicating that the extension
188    // needs to be restarted for any changes to take effect.
189    if (! parser.getNamedArguments().isEmpty())
190    {
191      adminActionsRequired.add(
192           "No configuration change has actually been applied.  The new " +
193                "configuration will not take effect until this pass-through " +
194                "authentication handler is disabled and re-enabled or until " +
195                "the server is restarted.");
196    }
197
198    return ResultCode.SUCCESS;
199  }
200
201
202
203  /**
204   * Performs any cleanup which may be necessary when this pass-through
205   * authentication handler is to be taken out of service.
206   */
207  public void finalizePassThroughAuthenticationHandler()
208  {
209    // No implementation is required.
210  }
211
212
213
214  /**
215   * Attempts to pass through authentication for the provided bind operation to
216   * the external service.
217   *
218   * @param  operationContext  The context for the bind operation.  It will not
219   *                           be {@code null}.
220   * @param  bindRequest       The bind request being processed.  It will not
221   *                           be {@code null}.
222   * @param  localEntry        The local entry for the account targeted by the
223   *                           bind operation.  It will not be {@code null}.
224   *
225   * @return  The result of the pass-through authentication attempt.  It must
226   *          not be {@code null}.
227   */
228  @NotNull()
229  public abstract PassThroughAuthenticationResult
230                       attemptPassThroughAuthentication(
231                            @NotNull final OperationContext operationContext,
232                            @NotNull final SimpleBindRequest bindRequest,
233                            @NotNull final Entry localEntry);
234
235
236
237  /**
238   * Retrieves a list of any handler-specific attributes that should be included
239   * in the monitor entry for the associated pluggable pass-through
240   * authentication plugin.
241   *
242   * @return  A list of any handler-specific attributes that should be included
243   *          in the monitor entry for the associated plugin.  It may be
244   *          {@code null} or empty if no handler-specific monitor attributes
245   *          should be included.
246   */
247  @Nullable()
248  public List<Attribute> getMonitorAttributes()
249  {
250    return Collections.emptyList();
251  }
252}