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