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 2010-2023 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.PasswordGeneratorConfig;
040import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
041import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
042import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
043import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
044import com.unboundid.ldap.sdk.LDAPException;
045import com.unboundid.ldap.sdk.ResultCode;
046import com.unboundid.util.ByteString;
047import com.unboundid.util.Extensible;
048import com.unboundid.util.ThreadSafety;
049import com.unboundid.util.ThreadSafetyLevel;
050import com.unboundid.util.args.ArgumentException;
051import com.unboundid.util.args.ArgumentParser;
052
053
054
055/**
056 * This class defines an API that must be implemented by extensions which
057 * generate user passwords.  This is primarily used when processing a password
058 * modify extended operation in order to generate a new password for the target
059 * user if the request did not explicitly provide the new password that should
060 * be used.  The generated password will not be subject to the constraints of
061 * any defined password validators.
062 * <BR>
063 * <H2>Configuring Password Generators</H2>
064 * In order to configure a password generator created using this API, use a
065 * command like:
066 * <PRE>
067 *      dsconfig create-password-generator \
068 *           --generator-name "<I>{generator-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>{generator-name}</I>" is the name to use for the password generator
075 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java class
076 * that extends {@code com.unboundid.directory.sdk.ds.api.PasswordGenerator},
077 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
078 * provide to the password generator.  If multiple arguments should be provided
079 * to the password generator, then the
080 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
081 * provided multiple times.
082 *
083 * @see  com.unboundid.directory.sdk.ds.scripting.ScriptedPasswordGenerator
084 */
085@Extensible()
086@DirectoryServerExtension()
087@DirectoryProxyServerExtension(appliesToLocalContent=true,
088     appliesToRemoteContent=false)
089@SynchronizationServerExtension(appliesToLocalContent=true,
090     appliesToSynchronizedContent=false)
091@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
092public abstract class PasswordGenerator
093       implements UnboundIDExtension, Reconfigurable<PasswordGeneratorConfig>,
094                  ExampleUsageProvider
095{
096  /**
097   * Creates a new instance of this password generator.  All password generator
098   * implementations must include a default constructor, but any initialization
099   * should generally be done in the {@code initializePasswordGenerator} method.
100   */
101  public PasswordGenerator()
102  {
103    // No implementation is required.
104  }
105
106
107
108  /**
109   * {@inheritDoc}
110   */
111  public abstract String getExtensionName();
112
113
114
115  /**
116   * {@inheritDoc}
117   */
118  public abstract String[] getExtensionDescription();
119
120
121
122  /**
123   * {@inheritDoc}
124   */
125  public void defineConfigArguments(final ArgumentParser parser)
126         throws ArgumentException
127  {
128    // No arguments will be allowed by default.
129  }
130
131
132
133  /**
134   * Initializes this password generator.
135   *
136   * @param  serverContext  A handle to the server context for the server in
137   *                        which this extension is running.
138   * @param  config         The general configuration for this password
139   *                        generator.
140   * @param  parser         The argument parser which has been initialized from
141   *                        the configuration for this password generator.
142   *
143   * @throws  LDAPException  If a problem occurs while initializing this
144   *                         password generator.
145   */
146  public void initializePasswordGenerator(
147                   final DirectoryServerContext serverContext,
148                   final PasswordGeneratorConfig config,
149                   final ArgumentParser parser)
150         throws LDAPException
151  {
152    // No initialization will be performed by default.
153  }
154
155
156
157  /**
158   * {@inheritDoc}
159   */
160  public boolean isConfigurationAcceptable(final PasswordGeneratorConfig config,
161                      final ArgumentParser parser,
162                      final List<String> unacceptableReasons)
163  {
164    // No extended validation will be performed by default.
165    return true;
166  }
167
168
169
170  /**
171   * {@inheritDoc}
172   */
173  public ResultCode applyConfiguration(final PasswordGeneratorConfig config,
174                                       final ArgumentParser parser,
175                                       final List<String> adminActionsRequired,
176                                       final List<String> messages)
177  {
178    // By default, no configuration changes will be applied.  If there are any
179    // arguments, then add an admin action message indicating that the extension
180    // needs to be restarted for any changes to take effect.
181    if (! parser.getNamedArguments().isEmpty())
182    {
183      adminActionsRequired.add(
184           "No configuration change has actually been applied.  The new " +
185                "configuration will not take effect until this password " +
186                "generator is disabled and re-enabled or until the server " +
187                "is restarted.");
188    }
189
190    return ResultCode.SUCCESS;
191  }
192
193
194
195  /**
196   * Performs any cleanup which may be necessary when this password generator is
197   * to be taken out of service.
198   */
199  public void finalizePasswordGenerator()
200  {
201    // No implementation is required.
202  }
203
204
205
206  /**
207   * Performs any processing which may be necessary to generate a user
208   * password.
209   *
210   * @param  userEntry  The entry of the user for whom to generate the password.
211   *
212   * @return  The generated password.
213   *
214   * @throws  LDAPException  If a problem occurs while attempting to generate a
215   *                         password for the user.
216   */
217  public abstract ByteString generatePassword(final Entry userEntry)
218         throws LDAPException;
219
220
221
222  /**
223   * {@inheritDoc}
224   */
225  public Map<List<String>,String> getExamplesArgumentSets()
226  {
227    return Collections.emptyMap();
228  }
229}