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