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