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