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.TrustManagerProviderCfgDefn;
032import org.opends.server.admin.std.server.TrustManagerProviderCfg;
033import org.opends.server.admin.std.server.RootCfg;
034import org.opends.server.admin.server.ServerManagementContext;
035import org.opends.server.api.TrustManagerProvider;
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 trust
047 * manager providers defined in the Directory Server.  It will initialize the
048 * trust manager providers when the server starts, and then will manage any
049 * additions, removals, or modifications to any trust manager providers while
050 * the server is running.
051 */
052public class TrustManagerProviderConfigManager
053       implements ConfigurationChangeListener<TrustManagerProviderCfg>,
054                  ConfigurationAddListener<TrustManagerProviderCfg>,
055                  ConfigurationDeleteListener<TrustManagerProviderCfg>
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 trust
063   * manager providers.
064   */
065  private final ConcurrentHashMap<DN,TrustManagerProvider> providers;
066
067  private final ServerContext serverContext;
068
069  /**
070   * Creates a new instance of this trust manager provider config manager.
071   *
072   * @param serverContext
073   *          The server context.
074   */
075  public TrustManagerProviderConfigManager(ServerContext serverContext)
076  {
077    this.serverContext = serverContext;
078    providers = new ConcurrentHashMap<>();
079  }
080
081  /**
082   * Initializes all trust 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 trust
087   *                           manager provider initialization process to fail.
088   *
089   * @throws  InitializationException  If a problem occurs while initializing
090   *                                   the trust manager providers that is not
091   *                                   related to the server configuration.
092   */
093  public void initializeTrustManagerProviders()
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 trust manager provider entries are added or
105    // removed.
106    rootConfiguration.addTrustManagerProviderAddListener(this);
107    rootConfiguration.addTrustManagerProviderDeleteListener(this);
108
109
110    //Initialize the existing trust manager providers.
111    for (String name : rootConfiguration.listTrustManagerProviders())
112    {
113      TrustManagerProviderCfg providerConfig =
114              rootConfiguration.getTrustManagerProvider(name);
115      providerConfig.addChangeListener(this);
116
117      if (providerConfig.isEnabled())
118      {
119        String className = providerConfig.getJavaClass();
120        try
121        {
122          TrustManagerProvider provider =
123               loadProvider(className, providerConfig, true);
124          providers.put(providerConfig.dn(), provider);
125          DirectoryServer.registerTrustManagerProvider(providerConfig.dn(),
126                                                       provider);
127        }
128        catch (InitializationException ie)
129        {
130          logger.error(ie.getMessageObject());
131          continue;
132        }
133      }
134    }
135  }
136
137
138
139  /** {@inheritDoc} */
140  public boolean isConfigurationAddAcceptable(
141          TrustManagerProviderCfg configuration,
142          List<LocalizableMessage> unacceptableReasons)
143  {
144    if (configuration.isEnabled())
145    {
146      // Get the name of the class and make sure we can instantiate it as a
147      // trust manager provider.
148      String className = configuration.getJavaClass();
149      try
150      {
151        loadProvider(className, configuration, false);
152      }
153      catch (InitializationException ie)
154      {
155        unacceptableReasons.add(ie.getMessageObject());
156        return false;
157      }
158    }
159
160    // If we've gotten here, then it's fine.
161    return true;
162  }
163
164
165
166  /** {@inheritDoc} */
167  public ConfigChangeResult applyConfigurationAdd(
168                                  TrustManagerProviderCfg configuration)
169  {
170    final ConfigChangeResult ccr = new ConfigChangeResult();
171
172    configuration.addChangeListener(this);
173
174    if (! configuration.isEnabled())
175    {
176      return ccr;
177    }
178
179    TrustManagerProvider provider = null;
180
181    // Get the name of the class and make sure we can instantiate it as a trust
182    // manager provider.
183    String className = configuration.getJavaClass();
184    try
185    {
186      provider = loadProvider(className, configuration, true);
187    }
188    catch (InitializationException ie)
189    {
190      ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode());
191      ccr.addMessage(ie.getMessageObject());
192    }
193
194    if (ccr.getResultCode() == ResultCode.SUCCESS)
195    {
196      providers.put(configuration.dn(), provider);
197      DirectoryServer.registerTrustManagerProvider(configuration.dn(),
198                                                   provider);
199    }
200
201    return ccr;
202  }
203
204
205
206  /** {@inheritDoc} */
207  public boolean isConfigurationDeleteAcceptable(
208                      TrustManagerProviderCfg configuration,
209                      List<LocalizableMessage> unacceptableReasons)
210  {
211    // FIXME -- We should try to perform some check to determine whether the
212    // provider is in use.
213    return true;
214  }
215
216
217
218  /** {@inheritDoc} */
219  public ConfigChangeResult applyConfigurationDelete(
220                                 TrustManagerProviderCfg configuration)
221  {
222    final ConfigChangeResult ccr = new ConfigChangeResult();
223
224    DirectoryServer.deregisterTrustManagerProvider(configuration.dn());
225
226    TrustManagerProvider provider = providers.remove(configuration.dn());
227    if (provider != null)
228    {
229      provider.finalizeTrustManagerProvider();
230    }
231
232    return ccr;
233  }
234
235
236
237  /** {@inheritDoc} */
238  public boolean isConfigurationChangeAcceptable(
239                      TrustManagerProviderCfg configuration,
240                      List<LocalizableMessage> unacceptableReasons)
241  {
242    if (configuration.isEnabled())
243    {
244      // Get the name of the class and make sure we can instantiate it as a
245      // trust manager provider.
246      String className = configuration.getJavaClass();
247      try
248      {
249        loadProvider(className, configuration, false);
250      }
251      catch (InitializationException ie)
252      {
253        unacceptableReasons.add(ie.getMessageObject());
254        return false;
255      }
256    }
257
258    // If we've gotten here, then it's fine.
259    return true;
260  }
261
262
263
264  /** {@inheritDoc} */
265  public ConfigChangeResult applyConfigurationChange(
266                                 TrustManagerProviderCfg configuration)
267  {
268    final ConfigChangeResult ccr = new ConfigChangeResult();
269
270
271    // Get the existing provider if it's already enabled.
272    TrustManagerProvider existingProvider = providers.get(configuration.dn());
273
274
275    // If the new configuration has the provider disabled, then disable it if it
276    // is enabled, or do nothing if it's already disabled.
277    if (! configuration.isEnabled())
278    {
279      if (existingProvider != null)
280      {
281        DirectoryServer.deregisterTrustManagerProvider(configuration.dn());
282
283        TrustManagerProvider provider = providers.remove(configuration.dn());
284        if (provider != null)
285        {
286          provider.finalizeTrustManagerProvider();
287        }
288      }
289
290      return ccr;
291    }
292
293
294    // Get the class for the trust manager provider.  If the provider is already
295    // enabled, then we shouldn't do anything with it although if the class has
296    // changed then we'll at least need to indicate that administrative action
297    // is required.  If the provider is disabled, then instantiate the class and
298    // initialize and register it as a trust manager provider.
299    String className = configuration.getJavaClass();
300    if (existingProvider != null)
301    {
302      if (! className.equals(existingProvider.getClass().getName()))
303      {
304        ccr.setAdminActionRequired(true);
305      }
306
307      return ccr;
308    }
309
310    TrustManagerProvider provider = null;
311    try
312    {
313      provider = loadProvider(className, configuration, true);
314    }
315    catch (InitializationException ie)
316    {
317      ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode());
318      ccr.addMessage(ie.getMessageObject());
319    }
320
321    if (ccr.getResultCode() == ResultCode.SUCCESS)
322    {
323      providers.put(configuration.dn(), provider);
324      DirectoryServer.registerTrustManagerProvider(configuration.dn(), provider);
325    }
326
327    return ccr;
328  }
329
330
331
332  /**
333   * Loads the specified class, instantiates it as a trust manager provider, and
334   * optionally initializes that instance.
335   *
336   * @param  className      The fully-qualified name of the trust manager
337   *                        provider class to load, instantiate, and initialize.
338   * @param  configuration  The configuration to use to initialize the trust
339   *                        manager provider.  It must not be {@code null}.
340   * @param  initialize     Indicates whether the trust manager provider
341   *                        instance should be initialized.
342   *
343   * @return  The possibly initialized trust manager provider.
344   *
345   * @throws  InitializationException  If a problem occurred while attempting to
346   *                                   initialize the trust manager provider.
347   */
348  private <T extends TrustManagerProviderCfg> TrustManagerProvider<T> loadProvider(
349                                   String className,
350                                   T configuration,
351                                   boolean initialize)
352          throws InitializationException
353  {
354    try
355    {
356      TrustManagerProviderCfgDefn definition =
357              TrustManagerProviderCfgDefn.getInstance();
358      ClassPropertyDefinition propertyDefinition =
359           definition.getJavaClassPropertyDefinition();
360      Class<? extends TrustManagerProvider> providerClass =
361           propertyDefinition.loadClass(className, TrustManagerProvider.class);
362      TrustManagerProvider<T> provider = providerClass.newInstance();
363
364      if (initialize)
365      {
366        provider.initializeTrustManagerProvider(configuration);
367      }
368      else
369      {
370        List<LocalizableMessage> unacceptableReasons = new ArrayList<>();
371        if (!provider.isConfigurationAcceptable(configuration, unacceptableReasons))
372        {
373          String reasons = Utils.joinAsString(".  ", unacceptableReasons);
374          throw new InitializationException(
375              ERR_CONFIG_TRUSTMANAGER_CONFIG_NOT_ACCEPTABLE.get(configuration.dn(), reasons));
376        }
377      }
378
379      return provider;
380    }
381    catch (Exception e)
382    {
383      LocalizableMessage message = ERR_CONFIG_TRUSTMANAGER_INITIALIZATION_FAILED.
384          get(className, configuration.dn(), stackTraceToSingleLineString(e));
385      throw new InitializationException(message, e);
386    }
387  }
388}
389