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