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