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 2010-2012 UnboundID Corp.
026     */
027    package com.unboundid.directory.sdk.ds.scripting;
028    
029    
030    
031    import java.security.cert.Certificate;
032    import java.util.List;
033    
034    import com.unboundid.directory.sdk.common.internal.Reconfigurable;
035    import com.unboundid.directory.sdk.ds.config.CertificateMapperConfig;
036    import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
037    import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
038    import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
039    import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
040    import com.unboundid.ldap.sdk.LDAPException;
041    import com.unboundid.ldap.sdk.ResultCode;
042    import com.unboundid.util.Extensible;
043    import com.unboundid.util.ThreadSafety;
044    import com.unboundid.util.ThreadSafetyLevel;
045    import com.unboundid.util.args.ArgumentException;
046    import com.unboundid.util.args.ArgumentParser;
047    
048    
049    
050    /**
051     * This class defines an API that must be implemented by scripted extensions
052     * which attempt to map a certificate presented by a client (e.g., via SSL or
053     * StartTLS) to a user defined in the server.  This is primarily used during
054     * the course of SASL EXTERNAL bind processing when a client uses a certificate
055     * to authenticate to the server.  Any information contained in the provided
056     * certificate chain (including the subject, fingerprint, validity, extensions,
057     * etc. of the client certificate, as well as any information about any issuer
058     * certificates) may be used to map information in the provided certificate
059     * chain to exactly one user in the server.  If the certificate cannot be mapped
060     * to any user, or if it is mapped to multiple users, then the authentication
061     * attempt must fail.
062     * <BR>
063     * <H2>Configuring Groovy-Scripted Certificate Mappers</H2>
064     * In order to configure a scripted certificate mapper based on this API and
065     * written in the Groovy scripting language, use a command like:
066     * <PRE>
067     *      dsconfig create-certificate-mapper \
068     *           --mapper-name "<I>{mapper-name}</I>" \
069     *           --type groovy-scripted \
070     *           --set enabled:true \
071     *           --set "script-class:<I>{class-name}</I>" \
072     *           --set "script-argument:<I>{name=value}</I>"
073     * </PRE>
074     * where "<I>{mapper-name}</I>" is the name to use for the certificate mapper
075     * instance, "<I>{class-name}</I>" is the fully-qualified name of the Groovy
076     * class written using this API, and "<I>{name=value}</I>" represents name-value
077     * pairs for any arguments to provide to the certificate mapper.  If multiple
078     * arguments should be provided to the certificate mapper, then the
079     * "<CODE>--set script-argument:<I>{name=value}</I></CODE>" option should be
080     * provided multiple times.
081     *
082     * @see  com.unboundid.directory.sdk.ds.api.CertificateMapper
083     */
084    @Extensible()
085    @DirectoryServerExtension()
086    @DirectoryProxyServerExtension(appliesToLocalContent=true,
087         appliesToRemoteContent=false)
088    @SynchronizationServerExtension(appliesToLocalContent=true,
089         appliesToSynchronizedContent=false)
090    @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
091    public abstract class ScriptedCertificateMapper
092           implements Reconfigurable<CertificateMapperConfig>
093    {
094      /**
095       * Creates a new instance of this certificate mapper.  All certificate mapper
096       * implementations must include a default constructor, but any initialization
097       * should generally be done in the {@code initializeCertificateMapper} method.
098       */
099      public ScriptedCertificateMapper()
100      {
101        // No implementation is required.
102      }
103    
104    
105    
106      /**
107       * {@inheritDoc}
108       */
109      public void defineConfigArguments(final ArgumentParser parser)
110             throws ArgumentException
111      {
112        // No arguments will be allowed by default.
113      }
114    
115    
116    
117      /**
118       * Initializes this certificate mapper.
119       *
120       * @param  serverContext  A handle to the server context for the server in
121       *                        which this extension is running.
122       * @param  config         The general configuration for this certificate
123       *                        mapper.
124       * @param  parser         The argument parser which has been initialized from
125       *                        the configuration for this certificate mapper.
126       *
127       * @throws  LDAPException  If a problem occurs while initializing this
128       *                         certificate mapper.
129       */
130      public void initializeCertificateMapper(
131                       final DirectoryServerContext serverContext,
132                       final CertificateMapperConfig config,
133                       final ArgumentParser parser)
134             throws LDAPException
135      {
136        // No initialization will be performed by default.
137      }
138    
139    
140    
141      /**
142       * {@inheritDoc}
143       */
144      public boolean isConfigurationAcceptable(final CertificateMapperConfig config,
145                          final ArgumentParser parser,
146                          final List<String> unacceptableReasons)
147      {
148        // No extended validation will be performed.
149        return true;
150      }
151    
152    
153    
154      /**
155       * {@inheritDoc}
156       */
157      public ResultCode applyConfiguration(final CertificateMapperConfig config,
158                                           final ArgumentParser parser,
159                                           final List<String> adminActionsRequired,
160                                           final List<String> messages)
161      {
162        // By default, no configuration changes will be applied.  If there are any
163        // arguments, then add an admin action message indicating that the extension
164        // needs to be restarted for any changes to take effect.
165        if (! parser.getNamedArguments().isEmpty())
166        {
167          adminActionsRequired.add(
168               "No configuration change has actually been applied.  The new " +
169                    "configuration will not take effect until this certificate " +
170                    "mapper is disabled and re-enabled or until the server is " +
171                    "restarted.");
172        }
173    
174        return ResultCode.SUCCESS;
175      }
176    
177    
178    
179      /**
180       * Performs any cleanup which may be necessary when this certificate mapper is
181       * to be taken out of service.
182       */
183      public void finalizeCertificateMapper()
184      {
185        // No implementation is required.
186      }
187    
188    
189    
190      /**
191       * Performs any processing which may be necessary to map the provided
192       * certificate chain to a user within the server.
193       *
194       * @param  certChain  The certificate chain presented by the client.
195       *
196       * @return  The DN of the user within the server to which the provided
197       *          certificate corresponds.
198       *
199       * @throws  LDAPException  If the presented certificate cannot be mapped to
200       *                         exactly one user in the server.
201       */
202      public abstract String mapCertificate(final Certificate[] certChain)
203             throws LDAPException;
204    }