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 2012-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.operation.SASLBindRequest;
039    import com.unboundid.directory.sdk.common.types.OperationContext;
040    import com.unboundid.directory.sdk.ds.config.SASLMechanismHandlerConfig;
041    import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
042    import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
043    import com.unboundid.directory.sdk.ds.types.SASLBindResult;
044    import com.unboundid.directory.sdk.ds.types.SASLBindResultFactory;
045    import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
046    import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
047    import com.unboundid.ldap.sdk.LDAPException;
048    import com.unboundid.ldap.sdk.ResultCode;
049    import com.unboundid.util.Extensible;
050    import com.unboundid.util.ThreadSafety;
051    import com.unboundid.util.ThreadSafetyLevel;
052    import com.unboundid.util.args.ArgumentException;
053    import com.unboundid.util.args.ArgumentParser;
054    
055    
056    
057    /**
058     * This class defines an API that must be implemented by extensions which add
059     * support for custom SASL mechanisms to the server, which can provide support
060     * for custom authentication (and optionally, authorization) methods.
061     * <BR>
062     * <H2>Configuring SASL Mechanism Handlers</H2>
063     * In order to configure a SASL mechanism handler created using this API, use a
064     * command like:
065     * <PRE>
066     *      dsconfig create-sasl-mechanism-handler \
067     *           --handler-name "<I>{handler-name}</I>" \
068     *           --type third-party \
069     *           --set enabled:true \
070     *           --set "extension-class:<I>{class-name}</I>" \
071     *           --set "extension-argument:<I>{name=value}</I>"
072     * </PRE>
073     * where "<I>{handler-name}</I>" is the name to use for the SASL mechanism
074     * handler instance, "<I>{class-name}</I>" is the fully-qualified name of the
075     * Java class that extends
076     * {@code com.unboundid.directory.sdk.ds.api.SASLMechanismHandler}, and
077     * "<I>{name=value}</I>" represents name-value pairs for any arguments to
078     * provide to the handler.  If multiple arguments should be provided to the SASL
079     * mechanism handler, then the
080     * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
081     * provided multiple times.
082     */
083    @Extensible()
084    @DirectoryServerExtension()
085    @DirectoryProxyServerExtension(appliesToLocalContent=true,
086         appliesToRemoteContent=true,
087         notes="Any SASL bind requests received by the Directory Proxy Server " +
088              "will be processed by the Directory Proxy Server itself rather " +
089              "than being forwarded to backend servers.  However, a SASL " +
090              "mechanism handler running in the Directory Proxy Server may " +
091              "perform internal operations which reference content in the " +
092              "backend servers as if it was contained locally in the server.")
093    @SynchronizationServerExtension(appliesToLocalContent=true,
094         appliesToSynchronizedContent=false)
095    @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
096    public abstract class SASLMechanismHandler
097           implements UnboundIDExtension,
098                      Reconfigurable<SASLMechanismHandlerConfig>,
099                      ExampleUsageProvider
100    {
101      /**
102       * Creates a new instance of this SASL mechanism handler.  All SASL
103       * mechanism handler implementations must include a default constructor, but
104       * any initialization
105       * should generally be done in the {@code initializeSASLMechanismHandler}
106       * method.
107       */
108      public SASLMechanismHandler()
109      {
110        // No implementation is required.
111      }
112    
113    
114    
115      /**
116       * {@inheritDoc}
117       */
118      public abstract String getExtensionName();
119    
120    
121    
122      /**
123       * {@inheritDoc}
124       */
125      public abstract String[] getExtensionDescription();
126    
127    
128    
129      /**
130       * {@inheritDoc}
131       */
132      public void defineConfigArguments(final ArgumentParser parser)
133             throws ArgumentException
134      {
135        // No arguments will be allowed by default.
136      }
137    
138    
139    
140      /**
141       * Initializes this SASL mechanism handler.
142       *
143       * @param  serverContext  A handle to the server context for the server in
144       *                        which this extension is running.
145       * @param  config         The general configuration for this SASL mechanism
146       *                        handler.
147       * @param  parser         The argument parser which has been initialized from
148       *                        the configuration for this SASL mechanism handler.
149       *
150       * @throws  LDAPException  If a problem occurs while initializing this SASL
151       *                         mechanism handler.
152       */
153      public void initializeSASLMechanismHandler(
154                       final DirectoryServerContext serverContext,
155                       final SASLMechanismHandlerConfig config,
156                       final ArgumentParser parser)
157             throws LDAPException
158      {
159        // No initialization will be performed by default.
160      }
161    
162    
163    
164      /**
165       * {@inheritDoc}
166       */
167      public boolean isConfigurationAcceptable(
168                          final SASLMechanismHandlerConfig config,
169                          final ArgumentParser parser,
170                          final List<String> unacceptableReasons)
171      {
172        // No extended validation will be performed by default.
173        return true;
174      }
175    
176    
177    
178      /**
179       * {@inheritDoc}
180       */
181      public ResultCode applyConfiguration(final SASLMechanismHandlerConfig config,
182                                           final ArgumentParser parser,
183                                           final List<String> adminActionsRequired,
184                                           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 SASL " +
194                    "mechanism handler is disabled and re-enabled or until the " +
195                    "server is restarted.");
196        }
197    
198        return ResultCode.SUCCESS;
199      }
200    
201    
202    
203      /**
204       * Performs any cleanup which may be necessary when this SASL mechanism
205       * handler is to be taken out of service.
206       */
207      public void finalizeSASLMechanismHandler()
208      {
209        // No implementation is required.
210      }
211    
212    
213    
214      /**
215       * Retrieves a list of the names of the SASL mechanisms supported by this
216       * SASL mechanism handler.  This method will be invoked only immediately after
217       * the {@link #initializeSASLMechanismHandler} method is called.
218       *
219       * @return  A list of the names of the SASL mechanisms supported by this SASL
220       *          mechanism handler.
221       */
222      public abstract List<String> getSASLMechanismNames();
223    
224    
225    
226      /**
227       * Indicates whether the SASL authentication process using the specified
228       * mechanism may be considered secure (i.e., that a third party able to
229       * observe the communication, potentially over an insecure communication
230       * channel, would not be able to reproduce the authentication process).
231       *
232       * @param  mechanism  The name of the mechanism for which to make the
233       *                    determination.  This will only be invoked with names of
234       *                    mechanisms returned by the
235       *                    {@link #getSASLMechanismNames} method.
236       *
237       * @return  {@code true} if the specified SASL mechanism should be considered
238       *          secure, or {@code false} if not.
239       */
240      public abstract boolean isSecure(final String mechanism);
241    
242    
243    
244      /**
245       * Indicates whether the SASL authentication process using the specified
246       * mechanism involves the use of a password stored locally in the server
247       * (optionally in combination with other forms of credentials).
248       *
249       * @param  mechanism  The name of the mechanism for which to make the
250       *                    determination.  This will only be invoked with names of
251       *                    mechanisms returned by the
252       *                    {@link #getSASLMechanismNames} method.
253       *
254       * @return  {@code true} if the specified SASL mechanism makes use of a local
255       *          password, or {@code false} if not.
256       */
257      public abstract boolean isPasswordBased(final String mechanism);
258    
259    
260    
261      /**
262       * Performs the appropriate processing for the provided SASL bind request.
263       *
264       * @param  operationContext  The context for the bind operation.
265       * @param  bindRequest       The SASL bind request to be processed.
266       * @param  resultFactory     A factory object that will be used to construct
267       *                           the result to return.
268       *
269       * @return  An object with information about the result of the SASL bind
270       *          processing.
271       */
272      public abstract SASLBindResult processSASLBind(
273                           final OperationContext operationContext,
274                           final SASLBindRequest bindRequest,
275                           final SASLBindResultFactory resultFactory);
276    
277    
278    
279      /**
280       * {@inheritDoc}
281       */
282      public Map<List<String>,String> getExamplesArgumentSets()
283      {
284        return Collections.emptyMap();
285      }
286    }