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-2014 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 password to be encoded.  It must not
297       *                        be {@code null}.  Note that there is no guarantee
298       *                        that password validators have yet been invoked for
299       *                        this password, so this password storage scheme
300       *                        implementation should not make any assumptions about
301       *                        the format of the plaintext password or whether it
302       *                        will actually be allowed for use in the entry.
303       * @param  userEntry      The complete entry for the user for whom the
304       *                        password is to be encoded.  This will not be
305       *                        {@code null} for schemes in which
306       *                        {@link #requiresUserEntry} returns {@code true}.
307       * @param  modifications  The set of modifications to be applied to the user
308       *                        entry.  This will generally be non-{@code null} only
309       *                        for operations that use a modify to change the user
310       *                        password.  If a modification list is provided, then
311       *                        it will contain the complete set of modifications
312       *                        for the operation, some of which may have no
313       *                        impact on password encoding.
314       * @param  deterministic  Indicates whether the password encoding should be
315       *                        deterministic.  If this is {@code true}, then the
316       *                        scheme should attempt to generate a consistent
317       *                        encoding for the password (e.g., by determining the
318       *                        salt from a normalized representation of the user's
319       *                        DN).  This will be used during LDIF import
320       *                        processing (and potentially at other times) to help
321       *                        ensure that if the LDIF file is imported into
322       *                        multiple servers, any clear-text password
323       *                        encountered in the LDIF file will have the same
324       *                        encoded representation on all servers.  Some
325       *                        password storage schemes may choose to ignore this
326       *                        property if it does not apply or is not possible to
327       *                        achieve.
328       * @param  includeScheme  Indicates whether to include the name of the scheme
329       *                        in curly braces before the encoded password.
330       *
331       * @return  The password that has been encoded using this storage
332       *          scheme.
333       *
334       * @throws  LDAPException  If a problem occurs while attempting to encode the
335       *                         password.
336       */
337      public abstract ByteString encodePassword(final ByteString plaintext,
338                                      final Entry userEntry,
339                                      final List<Modification> modifications,
340                                      final boolean deterministic,
341                                      final boolean includeScheme)
342             throws LDAPException;
343    
344    
345    
346      /**
347       * Indicates whether the provided plaintext password could have been used to
348       * generate the given encoded password.
349       *
350       * @param  plaintextPassword  The plaintext password provided by the user as
351       *                            part of a simple bind attempt.
352       * @param  storedPassword     The stored password to compare against the
353       *                            provided plaintext password.  It will not
354       *                            include the scheme name in curly braces.
355       * @param  userEntry          The complete entry for the user for whom the
356       *                            password is to be validated.  This will not be
357       *                            {@code null} for schemes in which
358       *                            {@link #requiresUserEntry} returns {@code true}.
359       *
360       * @return  {@code true} if the provided clear-text password could have been
361       *          used to generate the encoded password, or {@code false} if not.
362       */
363      public abstract boolean passwordMatches(final ByteString plaintextPassword,
364                                              final ByteString storedPassword,
365                                              final Entry userEntry);
366    
367    
368    
369      /**
370       * Attempts to determine the plaintext password used to generate the provided
371       * encoded password.  This method should only be called if the
372       * {@link #isReversible} method returns {@code true}.
373       *
374       * @param  storedPassword  The password for which to obtain the plaintext
375       *                         value.  It should not include the scheme name in
376       *                         curly braces.
377       * @param  userEntry       The complete entry for the user for whom the
378       *                         password is to be validated.  This will not be
379       *                         {@code null} for schemes in which
380       *                         {@link #requiresUserEntry} returns {@code true}.
381       *
382       * @return  The plaintext password obtained from the given encoded password.
383       *
384       * @throws  LDAPException  If this password storage scheme is not reversible,
385       *                         or if the provided value could not be decoded to
386       *                         its plaintext representation.
387       */
388      public abstract ByteString getPlaintextValue(final ByteString storedPassword,
389                                                   final Entry userEntry)
390             throws LDAPException;
391    
392    
393    
394      /**
395       * Indicates whether this password storage scheme provides the ability to
396       * encode passwords in the authentication password syntax as described in RFC
397       * 3112.
398       *
399       * @return  {@code true} if this password storage scheme supports the
400       *          authentication password syntax, or {@code false} if not.
401       */
402      public boolean supportsAuthPasswordSyntax()
403      {
404        return false;
405      }
406    
407    
408    
409      /**
410       * Retrieves the name that should be used to identify this password storage
411       * scheme when encoding passwords using the authentication password syntax as
412       * described in RFC 3112.  This should only be used if the
413       * {@link #supportsAuthPasswordSyntax} method returns {@code true}.
414       *
415       * @return  The name that should be used to identify this password storage
416       *          scheme when encoding passwords using the authentication password
417       *          syntax.
418       */
419      public String getAuthPasswordSchemeName()
420      {
421        return getStorageSchemeName();
422      }
423    
424    
425    
426      /**
427       * Encodes the provided plaintext password using the authentication password
428       * syntax as defined in RFC 3112.  This should only be used if the
429       * {@link #supportsAuthPasswordSyntax} method returns {@code true}.
430       *
431       * @param  plaintext      The plaintext password to be encoded.  It must not
432       *                        be {@code null}.  Note that there is no guarantee
433       *                        that password validators have yet been invoked for
434       *                        this password, so this password storage scheme
435       *                        implementation should not make any assumptions about
436       *                        the format of the plaintext password or whether it
437       *                        will actually be allowed for use in the entry.
438       * @param  userEntry      The complete entry for the user for whom the
439       *                        password is to be encoded.  This will not be
440       *                        {@code null} for schemes in which
441       *                        {@link #requiresUserEntry} returns {@code true}.
442       * @param  modifications  The set of modifications to be applied to the user
443       *                        entry.  This will generally be non-{@code null} only
444       *                        for operations that use a modify to change the user
445       *                        password.  If a modification list is provided, then
446       *                        it will contain the complete set of modifications
447       *                        for the operation, some of which may have no
448       *                        impact on password encoding.
449       * @param  deterministic  Indicates whether the password encoding should be
450       *                        deterministic.  If this is {@code true}, then the
451       *                        scheme should attempt to generate a consistent
452       *                        encoding for the password (e.g., by determining the
453       *                        salt from a normalized representation of the user's
454       *                        DN).  This will be used during LDIF import
455       *                        processing (and potentially at other times) to help
456       *                        ensure that if the LDIF file is imported into
457       *                        multiple servers, any clear-text password
458       *                        encountered in the LDIF file will have the same
459       *                        encoded representation on all servers.  Some
460       *                        password storage schemes may choose to ignore this
461       *                        property if it does not apply or is not possible to
462       *                        achieve.
463       *
464       * @return  The encoded representation of the provided password.
465       *
466       * @throws  LDAPException  If a problem occurs while encoding the provided
467       *                         password, or if this password storage scheme does
468       *                         not support the authentication password syntax.
469       */
470      public ByteString encodeAuthPassword(final ByteString plaintext,
471                                           final Entry userEntry,
472                                           final List<Modification> modifications,
473                                           final boolean deterministic)
474             throws LDAPException
475      {
476        throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
477             "This password storage scheme does not support the use of the " +
478             "authentication password syntax.");
479      }
480    
481    
482    
483      /**
484       * Indicates whether the provided plaintext password may be used to generate
485       * an encoded password with the given authInfo and authValue elements when
486       * using the authentication password syntax as defined in RFC 3112.  This
487       * should only be used if the {@link #supportsAuthPasswordSyntax} method
488       * returns {@code true}.
489       *
490       * @param  plaintextPassword  The plaintext password provided by the user.
491       * @param  authInfo           The authInfo component of the password encoded
492       *                            in the authentication password syntax.
493       * @param  authValue          The authValue component of the password encoded
494       *                            in the authentication password syntax.
495       * @param  userEntry          The complete entry for the user for whom the
496       *                            password is to be validated.  This will not be
497       *                            {@code null} for schemes in which
498       *                            {@link #requiresUserEntry} returns {@code true}.
499       *
500       * @return  {@code true} if the provided plaintext password could be used to
501       *          generate an encoded password with the given authInfo and authValue
502       *          portions, or {@code false} if not.
503       */
504      public boolean authPasswordMatches(final ByteString plaintextPassword,
505                                         final String authInfo,
506                                         final String authValue,
507                                         final Entry userEntry)
508      {
509        return false;
510      }
511    
512    
513    
514      /**
515       * Obtains the plaintext password that was used to generate an encoded
516       * password with the given authInfo and authValue elements when using the
517       * authentication password syntax as described in RFC 3112.  This should only
518       * be used if both the {@link #supportsAuthPasswordSyntax} and
519       * {@link #isReversible} methods return {@code true}.
520       *
521       * @param  authInfo   The authInfo component of the password encoded in the
522       *                    authentication password syntax.
523       * @param  authValue  The authValue component of the password encoded in the
524       *                    authentication password syntax.
525       * @param  userEntry  The complete entry for the user for whom the password is
526       *                    to be validated.  This will not be {@code null} for
527       *                    schemes in which {@link #requiresUserEntry} returns
528       *                    {@code true}.  The entry should not be altered in any
529       *                    way by this password storage scheme.
530       *
531       * @return  The plaintext password that was used to generate the encoded
532       *          password.
533       *
534       * @throws  LDAPException  If this password storage scheme is not reversible,
535       *                         if this password storage scheme does not support
536       *                         the authentication password syntax, or if some
537       *                         other problem is encountered while attempting to
538       *                         determine the plaintext password.
539       */
540      public ByteString getAuthPasswordPlaintextValue(final String authInfo,
541                                                      final String authValue,
542                                                      final Entry userEntry)
543             throws LDAPException
544      {
545        throw new LDAPException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
546             "This password storage scheme does not support the use of the " +
547             "authentication password syntax.");
548      }
549    
550    
551    
552      /**
553       * {@inheritDoc}
554       */
555      public Map<List<String>,String> getExamplesArgumentSets()
556      {
557        return Collections.emptyMap();
558      }
559    }