001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2006-2008 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2016 ForgeRock AS.
016 */
017package org.opends.server.core;
018
019import org.forgerock.i18n.LocalizableMessage;
020import org.forgerock.i18n.slf4j.LocalizedLogger;
021import org.forgerock.util.Utils;
022
023import java.util.ArrayList;
024import java.util.List;
025import java.util.concurrent.ConcurrentHashMap;
026
027import org.opends.server.admin.ClassPropertyDefinition;
028import org.opends.server.admin.server.ConfigurationAddListener;
029import org.opends.server.admin.server.ConfigurationChangeListener;
030import org.opends.server.admin.server.ConfigurationDeleteListener;
031import org.opends.server.admin.std.meta.KeyManagerProviderCfgDefn;
032import org.opends.server.admin.std.server.KeyManagerProviderCfg;
033import org.opends.server.admin.std.server.RootCfg;
034import org.opends.server.admin.server.ServerManagementContext;
035import org.opends.server.api.KeyManagerProvider;
036import org.forgerock.opendj.config.server.ConfigException;
037import org.forgerock.opendj.config.server.ConfigChangeResult;
038import org.forgerock.opendj.ldap.DN;
039import org.opends.server.types.InitializationException;
040import org.forgerock.opendj.ldap.ResultCode;
041
042import static org.opends.messages.ConfigMessages.*;
043import static org.opends.server.util.StaticUtils.*;
044
045/**
046 * This class defines a utility that will be used to manage the set of key
047 * manager providers defined in the Directory Server.  It will initialize the
048 * key manager providers when the server starts, and then will manage any
049 * additions, removals, or modifications to any key manager providers while
050 * the server is running.
051 */
052public class  KeyManagerProviderConfigManager
053       implements ConfigurationChangeListener<KeyManagerProviderCfg>,
054                  ConfigurationAddListener<KeyManagerProviderCfg>,
055                  ConfigurationDeleteListener<KeyManagerProviderCfg>
056
057{
058
059  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
060
061  /**
062   * A mapping between the DNs of the config entries and the associated key
063   * manager providers.
064   */
065  private final ConcurrentHashMap<DN,KeyManagerProvider> providers;
066
067  private final ServerContext serverContext;
068
069  /**
070   * Creates a new instance of this key manager provider config manager.
071   *
072   * @param serverContext
073   *          The server context.
074   */
075  public KeyManagerProviderConfigManager(ServerContext serverContext)
076  {
077    this.serverContext = serverContext;
078    providers = new ConcurrentHashMap<>();
079  }
080
081  /**
082   * Initializes all key manager providers currently defined in the Directory
083   * Server configuration.  This should only be called at Directory Server
084   * startup.
085   *
086   * @throws  ConfigException  If a configuration problem causes the key
087   *                           manager provider initialization process to fail.
088   *
089   * @throws  InitializationException  If a problem occurs while initializing
090   *                                   the key manager providers that is not
091   *                                   related to the server configuration.
092   */
093  public void initializeKeyManagerProviders()
094         throws ConfigException, InitializationException
095  {
096    // Get the root configuration object.
097    ServerManagementContext managementContext =
098         ServerManagementContext.getInstance();
099    RootCfg rootConfiguration =
100         managementContext.getRootConfiguration();
101
102
103    // Register as an add and delete listener with the root configuration so we
104    // can be notified if any key manager provider entries are added or removed.
105    rootConfiguration.addKeyManagerProviderAddListener(this);
106    rootConfiguration.addKeyManagerProviderDeleteListener(this);
107
108
109    //Initialize the existing key manager providers.
110    for (String name : rootConfiguration.listKeyManagerProviders())
111    {
112      KeyManagerProviderCfg providerConfig =
113              rootConfiguration.getKeyManagerProvider(name);
114      providerConfig.addChangeListener(this);
115
116      if (providerConfig.isEnabled())
117      {
118        String className = providerConfig.getJavaClass();
119        try
120        {
121          KeyManagerProvider provider =
122               loadProvider(className, providerConfig, true);
123          providers.put(providerConfig.dn(), provider);
124          DirectoryServer.registerKeyManagerProvider(providerConfig.dn(),
125                                                     provider);
126        }
127        catch (InitializationException ie)
128        {
129          logger.error(ie.getMessageObject());
130          continue;
131        }
132      }
133    }
134  }
135
136
137
138  /** {@inheritDoc} */
139  public boolean isConfigurationAddAcceptable(
140          KeyManagerProviderCfg configuration,
141          List<LocalizableMessage> unacceptableReasons)
142  {
143    if (configuration.isEnabled())
144    {
145      // Get the name of the class and make sure we can instantiate it as a
146      // key manager provider.
147      String className = configuration.getJavaClass();
148      try
149      {
150        loadProvider(className, configuration, false);
151      }
152      catch (InitializationException ie)
153      {
154        unacceptableReasons.add(ie.getMessageObject());
155        return false;
156      }
157    }
158
159    // If we've gotten here, then it's fine.
160    return true;
161  }
162
163
164
165  /** {@inheritDoc} */
166  public ConfigChangeResult applyConfigurationAdd(
167          KeyManagerProviderCfg configuration)
168  {
169    final ConfigChangeResult ccr = new ConfigChangeResult();
170
171    configuration.addChangeListener(this);
172
173    if (! configuration.isEnabled())
174    {
175      return ccr;
176    }
177
178    KeyManagerProvider provider = null;
179
180    // Get the name of the class and make sure we can instantiate it as a key
181    // manager provider.
182    String className = configuration.getJavaClass();
183    try
184    {
185      provider = loadProvider(className, configuration, true);
186    }
187    catch (InitializationException ie)
188    {
189      ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode());
190      ccr.addMessage(ie.getMessageObject());
191    }
192
193    if (ccr.getResultCode() == ResultCode.SUCCESS)
194    {
195      providers.put(configuration.dn(), provider);
196      DirectoryServer.registerKeyManagerProvider(configuration.dn(), provider);
197    }
198
199    return ccr;
200  }
201
202
203
204  /** {@inheritDoc} */
205  public boolean isConfigurationDeleteAcceptable(
206                      KeyManagerProviderCfg configuration,
207                      List<LocalizableMessage> unacceptableReasons)
208  {
209    // FIXME -- We should try to perform some check to determine whether the
210    // provider is in use.
211    return true;
212  }
213
214
215
216  /** {@inheritDoc} */
217  public ConfigChangeResult applyConfigurationDelete(
218                                 KeyManagerProviderCfg configuration)
219  {
220    final ConfigChangeResult ccr = new ConfigChangeResult();
221
222    DirectoryServer.deregisterKeyManagerProvider(configuration.dn());
223
224    KeyManagerProvider provider = providers.remove(configuration.dn());
225    if (provider != null)
226    {
227      provider.finalizeKeyManagerProvider();
228    }
229
230    return ccr;
231  }
232
233
234
235  /** {@inheritDoc} */
236  public boolean isConfigurationChangeAcceptable(
237                      KeyManagerProviderCfg configuration,
238                      List<LocalizableMessage> unacceptableReasons)
239  {
240    if (configuration.isEnabled())
241    {
242      // Get the name of the class and make sure we can instantiate it as a key
243      // manager provider.
244      String className = configuration.getJavaClass();
245      try
246      {
247        loadProvider(className, configuration, false);
248      }
249      catch (InitializationException ie)
250      {
251        unacceptableReasons.add(ie.getMessageObject());
252        return false;
253      }
254    }
255
256    // If we've gotten here, then it's fine.
257    return true;
258  }
259
260
261
262  /** {@inheritDoc} */
263  public ConfigChangeResult applyConfigurationChange(
264                                 KeyManagerProviderCfg configuration)
265  {
266    final ConfigChangeResult ccr = new ConfigChangeResult();
267
268
269    // Get the existing provider if it's already enabled.
270    KeyManagerProvider existingProvider = providers.get(configuration.dn());
271
272
273    // If the new configuration has the provider disabled, then disable it if it
274    // is enabled, or do nothing if it's already disabled.
275    if (! configuration.isEnabled())
276    {
277      if (existingProvider != null)
278      {
279        DirectoryServer.deregisterKeyManagerProvider(configuration.dn());
280
281        KeyManagerProvider provider = providers.remove(configuration.dn());
282        if (provider != null)
283        {
284          provider.finalizeKeyManagerProvider();
285        }
286      }
287
288      return ccr;
289    }
290
291
292    // Get the class for the key manager provider.  If the provider is already
293    // enabled, then we shouldn't do anything with it although if the class has
294    // changed then we'll at least need to indicate that administrative action
295    // is required.  If the provider is disabled, then instantiate the class and
296    // initialize and register it as a key manager provider.
297    String className = configuration.getJavaClass();
298    if (existingProvider != null)
299    {
300      if (! className.equals(existingProvider.getClass().getName()))
301      {
302        ccr.setAdminActionRequired(true);
303      }
304
305      return ccr;
306    }
307
308    KeyManagerProvider provider = null;
309    try
310    {
311      provider = loadProvider(className, configuration, true);
312    }
313    catch (InitializationException ie)
314    {
315      ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode());
316      ccr.addMessage(ie.getMessageObject());
317    }
318
319    if (ccr.getResultCode() == ResultCode.SUCCESS)
320    {
321      providers.put(configuration.dn(), provider);
322      DirectoryServer.registerKeyManagerProvider(configuration.dn(), provider);
323    }
324
325    return ccr;
326  }
327
328
329
330  /**
331   * Loads the specified class, instantiates it as a key manager provider, and
332   * optionally initializes that instance.
333   *
334   * @param  className      The fully-qualified name of the key manager
335   *                        provider class to load, instantiate, and initialize.
336   * @param  configuration  The configuration to use to initialize the key
337   *                        manager provider.  It must not be {@code null}.
338   * @param  initialize     Indicates whether the key manager provider instance
339   *                        should be initialized.
340   *
341   * @return  The possibly initialized key manager provider.
342   *
343   * @throws  InitializationException  If the provided configuration is not
344   *                                   acceptable, or if a problem occurred
345   *                                   while attempting to initialize the key
346   *                                   manager provider using that
347   *                                   configuration.
348   */
349  private KeyManagerProvider loadProvider(String className,
350                                          KeyManagerProviderCfg configuration,
351                                          boolean initialize)
352          throws InitializationException
353  {
354    try
355    {
356      KeyManagerProviderCfgDefn definition =
357              KeyManagerProviderCfgDefn.getInstance();
358      ClassPropertyDefinition propertyDefinition =
359           definition.getJavaClassPropertyDefinition();
360      Class<? extends KeyManagerProvider> providerClass =
361           propertyDefinition.loadClass(className, KeyManagerProvider.class);
362      KeyManagerProvider provider = providerClass.newInstance();
363
364
365      if (initialize)
366      {
367        provider.initializeKeyManagerProvider(configuration);
368      }
369      else
370      {
371        List<LocalizableMessage> unacceptableReasons = new ArrayList<>();
372        if (!provider.isConfigurationAcceptable(configuration, unacceptableReasons))
373        {
374          String reasons = Utils.joinAsString(".  ", unacceptableReasons);
375          throw new InitializationException(
376              ERR_CONFIG_KEYMANAGER_CONFIG_NOT_ACCEPTABLE.get(configuration.dn(), reasons));
377        }
378      }
379
380      return provider;
381    }
382    catch (InitializationException ie)
383    {
384      throw ie;
385    }
386    catch (Exception e)
387    {
388      LocalizableMessage message = ERR_CONFIG_KEYMANAGER_INITIALIZATION_FAILED.
389          get(className, configuration.dn(), stackTraceToSingleLineString(e));
390      throw new InitializationException(message, e);
391    }
392  }
393}
394