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 2013 UnboundID Corp.
026     */
027    package com.unboundid.directory.sdk.ds.api;
028    
029    
030    
031    import java.util.Collections;
032    import java.util.List;
033    import java.util.Map;
034    
035    import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
036    import com.unboundid.directory.sdk.common.internal.Reconfigurable;
037    import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
038    import com.unboundid.directory.sdk.common.types.Entry;
039    import com.unboundid.directory.sdk.ds.config.PasswordStorageSchemeConfig;
040    import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
041    import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
042    import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
043    import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
044    import com.unboundid.ldap.sdk.LDAPException;
045    import com.unboundid.ldap.sdk.Modification;
046    import com.unboundid.ldap.sdk.ResultCode;
047    import com.unboundid.util.ByteString;
048    import com.unboundid.util.Extensible;
049    import com.unboundid.util.ThreadSafety;
050    import com.unboundid.util.ThreadSafetyLevel;
051    import com.unboundid.util.args.ArgumentException;
052    import com.unboundid.util.args.ArgumentParser;
053    
054    
055    
056    /**
057     * This class defines an API that may be implemented by extensions which provide
058     * enhanced password storage scheme support.  Although the older
059     * {@link PasswordStorageScheme} API is still supported, this enhanced version
060     * is both simpler and provides additional functionality, including providing
061     * access to the user entry (which may be useful, for example, if salt or
062     * encryption information is to be derived from other content in the entry, or
063     * from another repository that can be accessed based on content in the entry).
064     * However, this API is generally simpler than the {@code PasswordStorageScheme}
065     * API, so it may be desirable for all new implementations to implement this API
066     * instead.
067     * <BR><BR>
068     * Encoded passwords may take one of two forms.  The first is the "user
069     * password" syntax, in which the encoded password is represented by the name of
070     * the storage scheme in curly braces followed by the transformed password
071     * (e.g., "{scheme}encoded").  This format isn't based on any defined standard,
072     * but is commonly used by a number of directory server implementations.  The
073     * second format is the authentication password syntax as described in RFC 3112,
074     * in which the encoded representation is broken into scheme, authInfo, and
075     * authValue segments separated by dollar signs (e.g.,
076     * "scheme$authInfo$authValue").  All password storage schemes are required to
077     * support the "user password" syntax and may optionally also support the
078     * authentication password syntax.
079     * <BR>
080     * <H2>Configuring Enhanced Password Storage Schemes</H2>
081     * In order to configure a password storage scheme created using this API, use
082     * a command like:
083     * <PRE>
084     *      dsconfig create-password-storage-scheme \
085     *           --scheme-name "<I>{scheme-name}</I>" \
086     *           --type third-party-enhanced \
087     *           --set enabled:true \
088     *           --set "extension-class:<I>{class-name}</I>" \
089     *           --set "extension-argument:<I>{name=value}</I>"
090     * </PRE>
091     * where "<I>{scheme-name}</I>" is the name to use for the password storage
092     * scheme instance, "<I>{class-name}</I>" is the fully-qualified name of the
093     * Java class that extends
094     * {@code com.unboundid.directory.sdk.ds.api.PasswordStorageScheme}, and
095     * "<I>{name=value}</I>" represents name-value pairs for any arguments to
096     * provide to the password storage scheme.  If multiple arguments should be
097     * provided to the password storage scheme, then the
098     * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
099     * provided multiple times.
100     *
101     * @see PasswordStorageScheme
102     */
103    @Extensible()
104    @DirectoryServerExtension()
105    @DirectoryProxyServerExtension(appliesToLocalContent=true,
106         appliesToRemoteContent=false)
107    @SynchronizationServerExtension(appliesToLocalContent=true,
108         appliesToSynchronizedContent=false)
109    @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
110    public abstract class EnhancedPasswordStorageScheme
111           implements UnboundIDExtension,
112                      Reconfigurable<PasswordStorageSchemeConfig>,
113                      ExampleUsageProvider
114    {
115      /**
116       * Creates a new instance of this password storage scheme.  All password
117       * storage scheme implementations must include a default constructor, but any
118       * initialization should generally be done in the
119       * {@code initializePasswordStorageScheme} method.
120       */
121      public EnhancedPasswordStorageScheme()
122      {
123        // No implementation is required.
124      }
125    
126    
127    
128      /**
129       * {@inheritDoc}
130       */
131      public abstract String getExtensionName();
132    
133    
134    
135      /**
136       * {@inheritDoc}
137       */
138      public abstract String[] getExtensionDescription();
139    
140    
141    
142      /**
143       * {@inheritDoc}
144       */
145      public void defineConfigArguments(final ArgumentParser parser)
146             throws ArgumentException
147      {
148        // No arguments will be allowed by default.
149      }
150    
151    
152    
153      /**
154       * Initializes this password storage scheme.
155       *
156       * @param  serverContext  A handle to the server context for the server in
157       *                        which this extension is running.
158       * @param  config         The general configuration for this password storage
159       *                        scheme.
160       * @param  parser         The argument parser which has been initialized from
161       *                        the configuration for this password storage scheme.
162       *
163       * @throws  LDAPException  If a problem occurs while initializing this
164       *                         password storage scheme.
165       */
166      public void initializePasswordStorageScheme(
167                       final DirectoryServerContext serverContext,
168                       final PasswordStorageSchemeConfig config,
169                       final ArgumentParser parser)
170             throws LDAPException
171      {
172        // No initialization will be performed by default.
173      }
174    
175    
176    
177      /**
178       * {@inheritDoc}
179       */
180      public boolean isConfigurationAcceptable(
181                          final PasswordStorageSchemeConfig config,
182                          final ArgumentParser parser,
183                          final List<String> unacceptableReasons)
184      {
185        // No extended validation will be performed by default.
186        return true;
187      }
188    
189    
190    
191      /**
192       * {@inheritDoc}
193       */
194      public ResultCode applyConfiguration(final PasswordStorageSchemeConfig config,
195                                           final ArgumentParser parser,
196                                           final List<String> adminActionsRequired,
197                                           final List<String> messages)
198      {
199        // By default, no configuration changes will be applied.  If there are any
200        // arguments, then add an admin action message indicating that the extension
201        // needs to be restarted for any changes to take effect.
202        if (! parser.getNamedArguments().isEmpty())
203        {
204          adminActionsRequired.add(
205               "No configuration change has actually been applied.  The new " +
206                    "configuration will not take effect until this password " +
207                    "storage scheme is disabled and re-enabled or until the " +
208                    "server is restarted.");
209        }
210    
211        return ResultCode.SUCCESS;
212      }
213    
214    
215    
216      /**
217       * Performs any cleanup which may be necessary when this password storage
218       * scheme is to be taken out of service.
219       */
220      public void finalizePasswordStorageScheme()
221      {
222        // No implementation is required.
223      }
224    
225    
226    
227      /**
228       * Retrieves the name for this password storage scheme.  This will be the
229       * identifier which appears in curly braces at the beginning of the encoded
230       * password.  The name should not include curly braces.
231       *
232       * @return  The name for this password storage scheme.
233       */
234      public abstract String getStorageSchemeName();
235    
236    
237    
238      /**
239       * Indicates whether this password storage scheme encodes passwords in a form
240       * that allows the original plaintext value to be obtained from the encoded
241       * representation.
242       *
243       * @return  {@code true} if the original plaintext password may be obtained
244       *          from the encoded password, or {@code false} if not.
245       */
246      public abstract boolean isReversible();
247    
248    
249    
250      /**
251       * Indicates whether this password storage scheme encodes passwords in a form
252       * that may be considered secure.  A storage scheme should only be considered
253       * secure if it is not possible to trivially determine a clear-text value
254       * which may be used to generate a given encoded representation.
255       *
256       * @return  {@code true} if this password storage scheme may be considered
257       *          secure, or {@code false} if not.
258       */
259      public abstract boolean isSecure();
260    
261    
262    
263      /**
264       * Indicates whether this password storage scheme requires access to the user
265       * entry in order to perform processing.  If the storage scheme does require
266       * access to the user entry (e.g., in order to obtain key or salt information
267       * from another attribute, or to use information in the entry to access
268       * information in another data store), then some features (e.g., the ability
269       * to perform extensible matching with password values, or the ability to use
270       * the encode-password tool to encode and compare passwords) may not be
271       * available.
272       * <BR><BR>
273       * Note that if this method returns {@code true}, then the server will never
274       * provide a {@code null} value for the {@code userEntry} parameter to methods
275       * that accept it.  However, if this method returns {@code false}, then there
276       * may be some instances in which the server may invoke those methods with a
277       * {@code null} value for the {@code userEntry} parameter (e.g., when invoked
278       * by the encode-password tool or when targeting a password with an extensible
279       * match search filter).
280       *
281       * @return  {@code true} if this password storage scheme requires access to
282       *          the user entry, or {@code false} if not.
283       */
284      public boolean requiresUserEntry()
285      {
286        return false;
287      }
288    
289    
290    
291      /**
292       * Encodes the provided plaintext password for this storage scheme,
293       * without the name of the associated scheme.  Note that the
294       * provided plaintext password should not be altered in any way.
295       *
296       * @param  plaintext      The plaintext version of the password.  This will
297       *                        not be {@code null}.
298       * @param  userEntry      The complete entry for the user for whom the
299       *                        password is to be encoded.  This will not be
300       *                        {@code null} for schemes in which
301       *                        {@link #requiresUserEntry} returns {@code true}.
302       * @param  modifications  The set of modifications to be applied to the user
303       *                        entry.  This will generally be non-{@code null} only
304       *                        for operations that use a modify to change the user
305       *                        password.  If a modification list is provided, then
306       *                        it will contain the complete set of modifications
307       *                        for the operation, some of which may have no
308       *                        impact on password encoding.
309       * @param  deterministic  Indicates whether the password encoding should be
310       *                        deterministic.  If this is {@code true}, then the
311       *                        scheme should attempt to generate a consistent
312       *                        encoding for the password (e.g., by determining the
313       *                        salt from a normalized representation of the user's
314       *                        DN).  This will be used during LDIF import
315       *                        processing (and potentially at other times) to help
316       *                        ensure that if the LDIF file is imported into
317       *                        multiple servers, any clear-text password
318       *                        encountered in the LDIF file will have the same
319       *                        encoded representation on all servers.  Some
320       *                        password storage schemes may choose to ignore this
321       *                        property if it does not apply or is not possible to
322       *                        achieve.
323       * @param  includeScheme  Indicates whether to include the name of the scheme
324       *                        in curly braces before the encoded password.
325       *
326       * @return  The password that has been encoded using this storage
327       *          scheme.
328       *
329       * @throws  LDAPException  If a problem occurs while attempting to encode the
330       *                         password.
331       */
332      public abstract ByteString encodePassword(final ByteString plaintext,
333                                      final Entry userEntry,
334                                      final List<Modification> modifications,
335                                      final boolean deterministic,
336                                      final boolean includeScheme)
337             throws LDAPException;
338    
339    
340    
341      /**
342       * Indicates whether the provided plaintext password could have been used to
343       * generate the given encoded password.
344       *
345       * @param  plaintextPassword  The plaintext password provided by the user as
346       *                            part of a simple bind attempt.
347       * @param  storedPassword     The stored password to compare against the
348       *                            provided plaintext password.  It will not
349       *                            include the scheme name in curly braces.
350       * @param  userEntry          The complete entry for the user for whom the
351       *                            password is to be validated.  This will not be
352       *                            {@code null} for schemes in which
353       *                            {@link #requiresUserEntry} returns {@code true}.
354       *
355       * @return  {@code true} if the provided clear-text password could have been
356       *          used to generate the encoded password, or {@code false} if not.
357       */
358      public abstract boolean passwordMatches(final ByteString plaintextPassword,
359                                              final ByteString storedPassword,
360                                              final Entry userEntry);
361    
362    
363    
364      /**
365       * Attempts to determine the plaintext password used to generate the provided
366       * encoded password.  This method should only be called if the
367       * {@link #isReversible} method returns {@code true}.
368       *
369       * @param  storedPassword  The password for which to obtain the plaintext
370       *                         value.  It should not include the scheme name in
371       *                         curly braces.
372       * @param  userEntry       The complete entry for the user for whom the
373       *                         password is to be validated.  This will not be
374       *                         {@code null} for schemes in which
375       *                         {@link #requiresUserEntry} returns {@code true}.
376       *
377       * @return  The plaintext password obtained from the given encoded password.
378       *
379       * @throws  LDAPException  If this password storage scheme is not reversible,
380       *                         or if the provided value could not be decoded to
381       *                         its plaintext representation.
382       */
383      public abstract ByteString getPlaintextValue(final ByteString storedPassword,
384                                                   final Entry userEntry)
385             throws LDAPException;
386    
387    
388    
389      /**
390       * Indicates whether this password storage scheme provides the ability to
391       * encode passwords in the authentication password syntax as described in RFC
392       * 3112.
393       *
394       * @return  {@code true} if this password storage scheme supports the
395       *          authentication password syntax, or {@code false} if not.
396       */
397      public boolean supportsAuthPasswordSyntax()
398      {
399        return false;
400      }
401    
402    
403    
404      /**
405       * Retrieves the name that should be used to identify this password storage
406       * scheme when encoding passwords using the authentication password syntax as
407       * described in RFC 3112.  This should only be used if the
408       * {@link #supportsAuthPasswordSyntax} method returns {@code true}.
409       *
410       * @return  The name that should be used to identify this password storage
411       *          scheme when encoding passwords using the authentication password
412       *          syntax.
413       */
414      public String getAuthPasswordSchemeName()
415      {
416        return getStorageSchemeName();
417      }
418    
419    
420    
421      /**
422       * Encodes the provided plaintext password using the authentication password
423       * syntax as defined in RFC 3112.  This should only be used if the
424       * {@link #supportsAuthPasswordSyntax} method returns {@code true}.
425       *
426       * @param  plaintext      The plaintext version of the password.  This will
427       *                        not be {@code null}.
428       * @param  userEntry      The complete entry for the user for whom the
429       *                        password is to be encoded.  This will not be
430       *                        {@code null} for schemes in which
431       *                        {@link #requiresUserEntry} returns {@code true}.
432       * @param  modifications  The set of modifications to be applied to the user
433       *                        entry.  This will generally be non-{@code null} only
434       *                        for operations that use a modify to change the user
435       *                        password.  If a modification list is provided, then
436       *                        it will contain the complete set of modifications
437       *                        for the operation, some of which may have no
438       *                        impact on password encoding.
439       * @param  deterministic  Indicates whether the password encoding should be
440       *                        deterministic.  If this is {@code true}, then the
441       *                        scheme should attempt to generate a consistent
442       *                        encoding for the password (e.g., by determining the
443       *                        salt from a normalized representation of the user's
444       *                        DN).  This will be used during LDIF import
445       *                        processing (and potentially at other times) to help
446       *                        ensure that if the LDIF file is imported into
447       *                        multiple servers, any clear-text password
448       *                        encountered in the LDIF file will have the same
449       *                        encoded representation on all servers.  Some
450       *                        password storage schemes may choose to ignore this
451       *                        property if it does not apply or is not possible to
452       *                        achieve.
453       *
454       * @return  The encoded representation of the provided password.
455       *
456       * @throws  LDAPException  If a problem occurs while encoding the provided
457       *                         password, or if this password storage scheme does
458       *                         not support the authentication password syntax.
459       */
460      public ByteString encodeAuthPassword(final ByteString plaintext,
461                                           final Entry userEntry,
462                                           final List<Modification> modifications,
463                                           final boolean deterministic)
464             throws LDAPException
465      {
466        throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
467             "This password storage scheme does not support the use of the " +
468             "authentication password syntax.");
469      }
470    
471    
472    
473      /**
474       * Indicates whether the provided plaintext password may be used to generate
475       * an encoded password with the given authInfo and authValue elements when
476       * using the authentication password syntax as defined in RFC 3112.  This
477       * should only be used if the {@link #supportsAuthPasswordSyntax} method
478       * returns {@code true}.
479       *
480       * @param  plaintextPassword  The plaintext password provided by the user.
481       * @param  authInfo           The authInfo component of the password encoded
482       *                            in the authentication password syntax.
483       * @param  authValue          The authValue component of the password encoded
484       *                            in the authentication password syntax.
485       * @param  userEntry          The complete entry for the user for whom the
486       *                            password is to be validated.  This will not be
487       *                            {@code null} for schemes in which
488       *                            {@link #requiresUserEntry} returns {@code true}.
489       *
490       * @return  {@code true} if the provided plaintext password could be used to
491       *          generate an encoded password with the given authInfo and authValue
492       *          portions, or {@code false} if not.
493       */
494      public boolean authPasswordMatches(final ByteString plaintextPassword,
495                                         final String authInfo,
496                                         final String authValue,
497                                         final Entry userEntry)
498      {
499        return false;
500      }
501    
502    
503    
504      /**
505       * Obtains the plaintext password that was used to generate an encoded
506       * password with the given authInfo and authValue elements when using the
507       * authentication password syntax as described in RFC 3112.  This should only
508       * be used if both the {@link #supportsAuthPasswordSyntax} and
509       * {@link #isReversible} methods return {@code true}.
510       *
511       * @param  authInfo   The authInfo component of the password encoded in the
512       *                    authentication password syntax.
513       * @param  authValue  The authValue component of the password encoded in the
514       *                    authentication password syntax.
515       * @param  userEntry  The complete entry for the user for whom the password is
516       *                    to be validated.  This will not be {@code null} for
517       *                    schemes in which {@link #requiresUserEntry} returns
518       *                    {@code true}.  The entry should not be altered in any
519       *                    way by this password storage scheme.
520       *
521       * @return  The plaintext password that was used to generate the encoded
522       *          password.
523       *
524       * @throws  LDAPException  If this password storage scheme is not reversible,
525       *                         if this password storage scheme does not support
526       *                         the authentication password syntax, or if some
527       *                         other problem is encountered while attempting to
528       *                         determine the plaintext password.
529       */
530      public ByteString getAuthPasswordPlaintextValue(final String authInfo,
531                                                      final String authValue,
532                                                      final Entry userEntry)
533             throws LDAPException
534      {
535        throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
536             "This password storage scheme does not support the use of the " +
537             "authentication password syntax.");
538      }
539    
540    
541    
542      /**
543       * {@inheritDoc}
544       */
545      public Map<List<String>,String> getExamplesArgumentSets()
546      {
547        return Collections.emptyMap();
548      }
549    }