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 2011-2023 Ping Identity Corporation
026 */
027package com.unboundid.directory.sdk.ds.api;
028
029
030
031import java.io.InputStream;
032import java.io.OutputStream;
033import java.util.Collections;
034import java.util.List;
035import java.util.Map;
036import javax.crypto.CipherInputStream;
037import javax.crypto.CipherOutputStream;
038
039import com.unboundid.directory.sdk.broker.internal.BrokerExtension;
040import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
041import com.unboundid.directory.sdk.common.internal.Reconfigurable;
042import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
043import com.unboundid.directory.sdk.ds.config.CipherStreamProviderConfig;
044import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
045import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
046import com.unboundid.ldap.sdk.LDAPException;
047import com.unboundid.ldap.sdk.ResultCode;
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 * provide access to cipher input streams and cipher output streams to be used
059 * by the server in order to read and write encrypted data.
060 * <BR>
061 * <H2>Configuring Cipher Stream Providers</H2>
062 * In order to configure a cipher stream provider created using this API, use a
063 * command like:
064 * <PRE>
065 *      dsconfig create-cipher-stream-provider \
066 *           --provider-name "<I>{provider-name}</I>" \
067 *           --type third-party \
068 *           --set enabled:true \
069 *           --set "extension-class:<I>{class-name}</I>" \
070 *           --set "extension-argument:<I>{name=value}</I>"
071 * </PRE>
072 * where "<I>{provider-name}</I>" is the name to use for the cipher stream
073 * provider instance, "<I>{class-name}</I>" is the fully-qualified name of the
074 * Java class that extends
075 * {@code com.unboundid.directory.sdk.ds.api.CipherStreamProvider},
076 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
077 * provide to the cipher stream provider.  If multiple arguments should be
078 * provided to the cipher stream provider, 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@BrokerExtension()
085@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
086public abstract class CipherStreamProvider
087       implements UnboundIDExtension,
088                  Reconfigurable<CipherStreamProviderConfig>,
089                  ExampleUsageProvider
090{
091  /**
092   * Creates a new instance of this cipher stream provider.  All cipher stream
093   * provider implementations must include a default constructor, but any
094   * initialization should generally be done in the
095   * {@code initializeCipherStreamProvider} method.
096   */
097  public CipherStreamProvider()
098  {
099    // No implementation is required.
100  }
101
102
103
104  /**
105   * {@inheritDoc}
106   */
107  public abstract String getExtensionName();
108
109
110
111  /**
112   * {@inheritDoc}
113   */
114  public abstract String[] getExtensionDescription();
115
116
117
118  /**
119   * {@inheritDoc}
120   */
121  public void defineConfigArguments(final ArgumentParser parser)
122         throws ArgumentException
123  {
124    // No arguments will be allowed by default.
125  }
126
127
128
129  /**
130   * Initializes this cipher stream provider.
131   *
132   * @param  serverContext  A handle to the server context for the server in
133   *                        which this extension is running.
134   * @param  config         The general configuration for this cipher stream
135   *                        provider.
136   * @param  parser         The argument parser which has been initialized from
137   *                        the configuration for this cipher stream provider.
138   *
139   * @throws  LDAPException  If a problem occurs while initializing this cipher
140   *                         stream provider.
141   */
142  public void initializeCipherStreamProvider(
143                   final DirectoryServerContext serverContext,
144                   final CipherStreamProviderConfig config,
145                   final ArgumentParser parser)
146         throws LDAPException
147  {
148    // No initialization will be performed by default.
149  }
150
151
152
153  /**
154   * {@inheritDoc}
155   */
156  public boolean isConfigurationAcceptable(
157                      final CipherStreamProviderConfig config,
158                      final ArgumentParser parser,
159                      final List<String> unacceptableReasons)
160  {
161    // No extended validation will be performed by default.
162    return true;
163  }
164
165
166
167  /**
168   * {@inheritDoc}
169   */
170  public ResultCode applyConfiguration(final CipherStreamProviderConfig config,
171                                       final ArgumentParser parser,
172                                       final List<String> adminActionsRequired,
173                                       final List<String> messages)
174  {
175    // By default, no configuration changes will be applied.  If there are any
176    // arguments, then add an admin action message indicating that the extension
177    // needs to be restarted for any changes to take effect.
178    if (! parser.getNamedArguments().isEmpty())
179    {
180      adminActionsRequired.add(
181           "No configuration change has actually been applied.  The new " +
182                "configuration will not take effect until this cipher stream " +
183                "provider is disabled and re-enabled or until the server is " +
184                "restarted.");
185    }
186
187    return ResultCode.SUCCESS;
188  }
189
190
191
192  /**
193   * Performs any cleanup which may be necessary when this cipher stream
194   * provider is to be taken out of service.
195   */
196  public void finalizeCipherStreamProvider()
197  {
198    // No implementation is required.
199  }
200
201
202
203  /**
204   * Wraps the provided input stream in a cipher input stream that can be used
205   * to decrypt data read from the given stream.
206   *
207   * @param  source  The input stream to be wrapped with a cipher input stream.
208   *
209   * @return  The cipher input stream which wraps the provided input stream.
210   *
211   * @throws  LDAPException  If a problem occurs while creating the cipher input
212   *                         stream.
213   */
214  public abstract CipherInputStream createCipherInputStream(
215                                         final InputStream source)
216         throws LDAPException;
217
218
219
220  /**
221   * Wraps the provided output stream in a cipher output stream that can be used
222   * to encrypt data written to the given stream.
223   *
224   * @param  target  The output stream to be wrapped with a cipher output
225   *                 stream.
226   *
227   * @return  The cipher output stream which wraps the provided output stream.
228   *
229   * @throws  LDAPException  If a problem occurs while creating the cipher
230   *                         output stream.
231   */
232  public abstract CipherOutputStream createCipherOutputStream(
233                                          final OutputStream target)
234         throws LDAPException;
235
236
237
238  /**
239   * Wraps the provided input stream in a cipher input stream that can be used
240   * to decrypt data read from the given stream.  This method is primarily
241   * intended to verify that the cipher stream provider can still be used to
242   * read the encryption settings database on a fresh startup, so if possible,
243   * it should not use a precomputed encryption key or any other cached data.
244   *
245   * @param  source            The input stream to be wrapped with a cipher
246   *                           input stream.
247   * @param  allowInteractive  Indicates whether to allow use of the method in
248   *                           an interactive context.
249   *
250   * @return  The cipher input stream that wraps the provided input stream.
251   *
252   * @throws  LDAPException  If a problem occurs while creating the cipher
253   *                         input stream.
254   */
255  public CipherInputStream createCipherInputStreamWithoutCaching(
256                                         final InputStream source,
257                                         final boolean allowInteractive)
258         throws LDAPException
259  {
260    if (allowInteractive)
261    {
262      return createCipherInputStream(source);
263    }
264    else
265    {
266      throw new LDAPException(ResultCode.UNAVAILABLE,
267           "The third-party cipher stream provider does not support " +
268                "obtaining a cipher input stream with uncached data in a " +
269                "non-interactive manner.");
270    }
271  }
272
273
274
275  /**
276   * Retrieves a map with information about any backup compatibility properties
277   * that are specific to this cipher stream provider.
278   *
279   * @return  A map with information about any backup compatibility properties
280   *          that are specific to this cipher stream provider.  It may be
281   *          {@code null} or empty if there are no provider-specific
282   *          properties.
283   */
284  public Map<String,String> getBackupCompatibilityProperties()
285  {
286    // No properties will be added by default.
287    return null;
288  }
289
290
291
292  /**
293   * Examines the provided set of backup compatibility properties to determine
294   * whether there might be any warning or error conditions that may interfere
295   * with the ability to restore a backup of the encryption settings database.
296   * The default implementation does not do anything, but subclasses may
297   * override this method to provide any appropriate warning and error messages.
298   *
299   * @param  sourceProperties  A map of properties (obtained from the
300   *                           {@link #getBackupCompatibilityProperties} method)
301   *                           from the backup to be restore.  The contents of
302   *                           this map must not be altered.
303   * @param  targetProperties  A map of properties (obtained from the
304   *                           {@link #getBackupCompatibilityProperties} method)
305   *                           from the server in which the backup is to be
306   *                           restored.  The contents of this map must not be
307   *                           altered.
308   * @param  errorMessages     A list that may be updated with messages about
309   *                           any compatibility errors that have been
310   *                           identified.  If any compatibility errors are
311   *                           identified, the restore will be aborted.
312   * @param  warningMessages   A list that may be updated with messages about
313   *                           any compatibility warnings that have been
314   *                           identified.  If any compatibility warnings are
315   *                           identified, they will be presented to a user
316   *                           attempting a restore, but the user may choose to
317   *                           ignore them if they are certain that the issue
318   *                           will not cause any problems.
319   */
320  public void identifyBackupCompatibilityProblems(
321                   final Map<String,String> sourceProperties,
322                   final Map<String,String> targetProperties,
323                   final List<CharSequence> errorMessages,
324                   final List<CharSequence> warningMessages)
325  {
326    // No processing will be performed by default.
327  }
328
329
330
331  /**
332   * Retrieves a list of human-readable string representations for the
333   * provided cipher-stream-provider-specific backup compatibility properties.
334   * The list returned does not need to have a one-to-one mapping with the
335   * properties (e.g., it may omit information about some properties, or it may
336   * combine information from multiple properties into a single string, or it
337   * may convert one property into multiple strings).  It may also be
338   * {@code null} if this cipher stream provider does not expect to have any
339   * provider-specific properties.
340   *
341   * @param  propertyMap  A map of the property names and the associated values
342   *                      to use in obtaining the human-readable string
343   *                      representations.
344   *
345   * @return  A list of human-readable string representations for the
346   *          provider-specific backup compatibility properties, or {@code null}
347   *          if this cipher stream provider does not expect to have any
348   *          provider-specific properties.
349   */
350  public List<String> getBackupCompatibilityPropertyStrings(
351                           final Map<String,String> propertyMap)
352  {
353    // No property strings will be returned by default.
354    return null;
355  }
356
357
358
359  /**
360   * Retrieves a list of messages that should be logged (and made available in
361   * the output) when backing up an encryption settings database protected with
362   * this cipher stream provider.  For example, this may be used to warn about
363   * additional files that may also need to be backed up separately (e.g., an
364   * encryption key stored in a separate file).
365   *
366   * @return  A list of messages that should be logged when backing up an
367   *          encryption settings database protected with this cipher stream
368   *          provider.  It may be {@code null} or empty if no log messages are
369   *          needed.
370   */
371  public List<String> getBackupLogMessages()
372  {
373    // No messages will be logged by default.
374    return null;
375  }
376
377
378
379  /**
380   * {@inheritDoc}
381   */
382  public Map<List<String>,String> getExamplesArgumentSets()
383  {
384    return Collections.emptyMap();
385  }
386}