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     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
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     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.core;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.lang.reflect.Method;
033    import java.util.ArrayList;
034    import java.util.Iterator;
035    import java.util.List;
036    import java.util.concurrent.ConcurrentHashMap;
037    
038    import org.opends.server.admin.ClassPropertyDefinition;
039    import org.opends.server.admin.server.ConfigurationAddListener;
040    import org.opends.server.admin.server.ConfigurationChangeListener;
041    import org.opends.server.admin.server.ConfigurationDeleteListener;
042    import org.opends.server.admin.std.meta.TrustManagerProviderCfgDefn;
043    import org.opends.server.admin.std.server.TrustManagerProviderCfg;
044    import org.opends.server.admin.std.server.RootCfg;
045    import org.opends.server.admin.server.ServerManagementContext;
046    import org.opends.server.api.TrustManagerProvider;
047    import org.opends.server.config.ConfigException;
048    import org.opends.server.types.ConfigChangeResult;
049    import org.opends.server.types.DN;
050    
051    
052    import org.opends.server.types.InitializationException;
053    import org.opends.server.types.ResultCode;
054    
055    import static org.opends.messages.ConfigMessages.*;
056    
057    import static org.opends.server.util.StaticUtils.*;
058    import org.opends.server.loggers.ErrorLogger;
059    
060    
061    /**
062     * This class defines a utility that will be used to manage the set of trust
063     * manager providers defined in the Directory Server.  It will initialize the
064     * trust manager providers when the server starts, and then will manage any
065     * additions, removals, or modifications to any trust manager providers while
066     * the server is running.
067     */
068    public class TrustManagerProviderConfigManager
069           implements ConfigurationChangeListener<TrustManagerProviderCfg>,
070                      ConfigurationAddListener<TrustManagerProviderCfg>,
071                      ConfigurationDeleteListener<TrustManagerProviderCfg>
072    
073    {
074      // A mapping between the DNs of the config entries and the associated trust
075      // manager providers.
076      private ConcurrentHashMap<DN,TrustManagerProvider> providers;
077    
078    
079    
080      /**
081       * Creates a new instance of this trust manager provider config manager.
082       */
083      public TrustManagerProviderConfigManager()
084      {
085        providers = new ConcurrentHashMap<DN,TrustManagerProvider>();
086      }
087    
088    
089    
090      /**
091       * Initializes all trust manager providers currently defined in the Directory
092       * Server configuration.  This should only be called at Directory Server
093       * startup.
094       *
095       * @throws  ConfigException  If a configuration problem causes the trust
096       *                           manager provider initialization process to fail.
097       *
098       * @throws  InitializationException  If a problem occurs while initializing
099       *                                   the trust manager providers that is not
100       *                                   related to the server configuration.
101       */
102      public void initializeTrustManagerProviders()
103             throws ConfigException, InitializationException
104      {
105        // Get the root configuration object.
106        ServerManagementContext managementContext =
107             ServerManagementContext.getInstance();
108        RootCfg rootConfiguration =
109             managementContext.getRootConfiguration();
110    
111    
112        // Register as an add and delete listener with the root configuration so we
113        // can be notified if any trust manager provider entries are added or
114        // removed.
115        rootConfiguration.addTrustManagerProviderAddListener(this);
116        rootConfiguration.addTrustManagerProviderDeleteListener(this);
117    
118    
119        //Initialize the existing trust manager providers.
120        for (String name : rootConfiguration.listTrustManagerProviders())
121        {
122          TrustManagerProviderCfg providerConfig =
123                  rootConfiguration.getTrustManagerProvider(name);
124          providerConfig.addChangeListener(this);
125    
126          if (providerConfig.isEnabled())
127          {
128            String className = providerConfig.getJavaClass();
129            try
130            {
131              TrustManagerProvider provider =
132                   loadProvider(className, providerConfig, true);
133              providers.put(providerConfig.dn(), provider);
134              DirectoryServer.registerTrustManagerProvider(providerConfig.dn(),
135                                                           provider);
136            }
137            catch (InitializationException ie)
138            {
139              ErrorLogger.logError(ie.getMessageObject());
140              continue;
141            }
142          }
143        }
144      }
145    
146    
147    
148      /**
149       * {@inheritDoc}
150       */
151      public boolean isConfigurationAddAcceptable(
152              TrustManagerProviderCfg configuration,
153              List<Message> unacceptableReasons)
154      {
155        if (configuration.isEnabled())
156        {
157          // Get the name of the class and make sure we can instantiate it as a
158          // trust manager provider.
159          String className = configuration.getJavaClass();
160          try
161          {
162            loadProvider(className, configuration, false);
163          }
164          catch (InitializationException ie)
165          {
166            unacceptableReasons.add(ie.getMessageObject());
167            return false;
168          }
169        }
170    
171        // If we've gotten here, then it's fine.
172        return true;
173      }
174    
175    
176    
177      /**
178       * {@inheritDoc}
179       */
180      public ConfigChangeResult applyConfigurationAdd(
181                                      TrustManagerProviderCfg configuration)
182      {
183        ResultCode        resultCode          = ResultCode.SUCCESS;
184        boolean           adminActionRequired = false;
185        ArrayList<Message> messages            = new ArrayList<Message>();
186    
187        configuration.addChangeListener(this);
188    
189        if (! configuration.isEnabled())
190        {
191          return new ConfigChangeResult(resultCode, adminActionRequired, messages);
192        }
193    
194        TrustManagerProvider provider = null;
195    
196        // Get the name of the class and make sure we can instantiate it as a trust
197        // manager provider.
198        String className = configuration.getJavaClass();
199        try
200        {
201          provider = loadProvider(className, configuration, true);
202        }
203        catch (InitializationException ie)
204        {
205          if (resultCode == ResultCode.SUCCESS)
206          {
207            resultCode = DirectoryServer.getServerErrorResultCode();
208          }
209    
210          messages.add(ie.getMessageObject());
211        }
212    
213        if (resultCode == ResultCode.SUCCESS)
214        {
215          providers.put(configuration.dn(), provider);
216          DirectoryServer.registerTrustManagerProvider(configuration.dn(),
217                                                       provider);
218        }
219    
220        return new ConfigChangeResult(resultCode, adminActionRequired, messages);
221      }
222    
223    
224    
225      /**
226       * {@inheritDoc}
227       */
228      public boolean isConfigurationDeleteAcceptable(
229                          TrustManagerProviderCfg configuration,
230                          List<Message> unacceptableReasons)
231      {
232        // FIXME -- We should try to perform some check to determine whether the
233        // provider is in use.
234        return true;
235      }
236    
237    
238    
239      /**
240       * {@inheritDoc}
241       */
242      public ConfigChangeResult applyConfigurationDelete(
243                                     TrustManagerProviderCfg configuration)
244      {
245        ResultCode        resultCode          = ResultCode.SUCCESS;
246        boolean           adminActionRequired = false;
247        ArrayList<Message> messages            = new ArrayList<Message>();
248    
249        DirectoryServer.deregisterTrustManagerProvider(configuration.dn());
250    
251        TrustManagerProvider provider = providers.remove(configuration.dn());
252        if (provider != null)
253        {
254          provider.finalizeTrustManagerProvider();
255        }
256    
257        return new ConfigChangeResult(resultCode, adminActionRequired, messages);
258      }
259    
260    
261    
262      /**
263       * {@inheritDoc}
264       */
265      public boolean isConfigurationChangeAcceptable(
266                          TrustManagerProviderCfg configuration,
267                          List<Message> unacceptableReasons)
268      {
269        if (configuration.isEnabled())
270        {
271          // Get the name of the class and make sure we can instantiate it as a
272          // trust manager provider.
273          String className = configuration.getJavaClass();
274          try
275          {
276            loadProvider(className, configuration, false);
277          }
278          catch (InitializationException ie)
279          {
280            unacceptableReasons.add(ie.getMessageObject());
281            return false;
282          }
283        }
284    
285        // If we've gotten here, then it's fine.
286        return true;
287      }
288    
289    
290    
291      /**
292       * {@inheritDoc}
293       */
294      public ConfigChangeResult applyConfigurationChange(
295                                     TrustManagerProviderCfg configuration)
296      {
297        ResultCode        resultCode          = ResultCode.SUCCESS;
298        boolean           adminActionRequired = false;
299        ArrayList<Message> messages            = new ArrayList<Message>();
300    
301    
302        // Get the existing provider if it's already enabled.
303        TrustManagerProvider existingProvider = providers.get(configuration.dn());
304    
305    
306        // If the new configuration has the provider disabled, then disable it if it
307        // is enabled, or do nothing if it's already disabled.
308        if (! configuration.isEnabled())
309        {
310          if (existingProvider != null)
311          {
312            DirectoryServer.deregisterTrustManagerProvider(configuration.dn());
313    
314            TrustManagerProvider provider = providers.remove(configuration.dn());
315            if (provider != null)
316            {
317              provider.finalizeTrustManagerProvider();
318            }
319          }
320    
321          return new ConfigChangeResult(resultCode, adminActionRequired, messages);
322        }
323    
324    
325        // Get the class for the trust manager provider.  If the provider is already
326        // enabled, then we shouldn't do anything with it although if the class has
327        // changed then we'll at least need to indicate that administrative action
328        // is required.  If the provider is disabled, then instantiate the class and
329        // initialize and register it as a trust manager provider.
330        String className = configuration.getJavaClass();
331        if (existingProvider != null)
332        {
333          if (! className.equals(existingProvider.getClass().getName()))
334          {
335            adminActionRequired = true;
336          }
337    
338          return new ConfigChangeResult(resultCode, adminActionRequired, messages);
339        }
340    
341        TrustManagerProvider provider = null;
342        try
343        {
344          provider = loadProvider(className, configuration, true);
345        }
346        catch (InitializationException ie)
347        {
348          if (resultCode == ResultCode.SUCCESS)
349          {
350            resultCode = DirectoryServer.getServerErrorResultCode();
351          }
352    
353          messages.add(ie.getMessageObject());
354        }
355    
356        if (resultCode == ResultCode.SUCCESS)
357        {
358          providers.put(configuration.dn(), provider);
359          DirectoryServer.registerTrustManagerProvider(configuration.dn(),
360                                                       provider);
361        }
362    
363        return new ConfigChangeResult(resultCode, adminActionRequired, messages);
364      }
365    
366    
367    
368      /**
369       * Loads the specified class, instantiates it as a trust manager provider, and
370       * optionally initializes that instance.
371       *
372       * @param  className      The fully-qualified name of the trust manager
373       *                        provider class to load, instantiate, and initialize.
374       * @param  configuration  The configuration to use to initialize the trust
375       *                        manager provider.  It must not be {@code null}.
376       * @param  initialize     Indicates whether the trust manager provider
377       *                        instance should be initialized.
378       *
379       * @return  The possibly initialized trust manager provider.
380       *
381       * @throws  InitializationException  If a problem occurred while attempting to
382       *                                   initialize the trust manager provider.
383       */
384      private TrustManagerProvider loadProvider(
385                                       String className,
386                                       TrustManagerProviderCfg configuration,
387                                       boolean initialize)
388              throws InitializationException
389      {
390        try
391        {
392          TrustManagerProviderCfgDefn definition =
393                  TrustManagerProviderCfgDefn.getInstance();
394          ClassPropertyDefinition propertyDefinition =
395               definition.getJavaClassPropertyDefinition();
396          Class<? extends TrustManagerProvider> providerClass =
397               propertyDefinition.loadClass(className, TrustManagerProvider.class);
398          TrustManagerProvider provider = providerClass.newInstance();
399    
400          if (initialize)
401          {
402            Method method = provider.getClass().getMethod(
403                "initializeTrustManagerProvider",
404                configuration.configurationClass());
405            method.invoke(provider, configuration);
406          }
407          else
408          {
409            Method method =
410                 provider.getClass().getMethod("isConfigurationAcceptable",
411                                               TrustManagerProviderCfg.class,
412                                               List.class);
413    
414            List<Message> unacceptableReasons = new ArrayList<Message>();
415            Boolean acceptable = (Boolean) method.invoke(provider, configuration,
416                                                         unacceptableReasons);
417            if (! acceptable)
418            {
419              StringBuilder buffer = new StringBuilder();
420              if (! unacceptableReasons.isEmpty())
421              {
422                Iterator<Message> iterator = unacceptableReasons.iterator();
423                buffer.append(iterator.next());
424                while (iterator.hasNext())
425                {
426                  buffer.append(".  ");
427                  buffer.append(iterator.next());
428                }
429              }
430    
431              Message message = ERR_CONFIG_TRUSTMANAGER_CONFIG_NOT_ACCEPTABLE.get(
432                  String.valueOf(configuration.dn()), buffer.toString());
433              throw new InitializationException(message);
434            }
435          }
436    
437          return provider;
438        }
439        catch (Exception e)
440        {
441          Message message = ERR_CONFIG_TRUSTMANAGER_INITIALIZATION_FAILED.
442              get(className, String.valueOf(configuration.dn()),
443                  stackTraceToSingleLineString(e));
444          throw new InitializationException(message, e);
445        }
446      }
447    }
448