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.SASLMechanismHandlerCfgDefn; 043 import org.opends.server.admin.std.server.SASLMechanismHandlerCfg; 044 import org.opends.server.admin.std.server.RootCfg; 045 import org.opends.server.admin.server.ServerManagementContext; 046 import org.opends.server.api.SASLMechanismHandler; 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 SASL 063 * mechanism handlers defined in the Directory Server. It will initialize the 064 * handlers when the server starts, and then will manage any additions, 065 * removals, or modifications to any SASL mechanism handlers while the server is 066 * running. 067 */ 068 public class SASLConfigManager implements 069 ConfigurationChangeListener<SASLMechanismHandlerCfg>, 070 ConfigurationAddListener<SASLMechanismHandlerCfg>, 071 ConfigurationDeleteListener<SASLMechanismHandlerCfg> 072 073 { 074 // A mapping between the DNs of the config entries and the 075 // associated SASL 076 // mechanism handlers. 077 private ConcurrentHashMap<DN,SASLMechanismHandler> handlers; 078 079 080 081 /** 082 * Creates a new instance of this SASL mechanism handler config manager. 083 */ 084 public SASLConfigManager() 085 { 086 handlers = new ConcurrentHashMap<DN,SASLMechanismHandler>(); 087 } 088 089 090 091 /** 092 * Initializes all SASL mechanism hanlders currently defined in the Directory 093 * Server configuration. This should only be called at Directory Server 094 * startup. 095 * 096 * @throws ConfigException If a configuration problem causes the SASL 097 * mechanism handler initialization process to fail. 098 * 099 * @throws InitializationException If a problem occurs while initializing 100 * the SASL mechanism handlers that is not 101 * related to the server configuration. 102 */ 103 public void initializeSASLMechanismHandlers() 104 throws ConfigException, InitializationException 105 { 106 // Get the root configuration object. 107 ServerManagementContext managementContext = 108 ServerManagementContext.getInstance(); 109 RootCfg rootConfiguration = 110 managementContext.getRootConfiguration(); 111 112 113 // Register as an add and delete listener with the root configuration so we 114 // can be notified if any SASL mechanism handler entries are added or 115 // removed. 116 rootConfiguration.addSASLMechanismHandlerAddListener(this); 117 rootConfiguration.addSASLMechanismHandlerDeleteListener(this); 118 119 120 //Initialize the existing SASL mechanism handlers. 121 for (String handlerName : rootConfiguration.listSASLMechanismHandlers()) 122 { 123 SASLMechanismHandlerCfg handlerConfiguration = 124 rootConfiguration.getSASLMechanismHandler(handlerName); 125 handlerConfiguration.addChangeListener(this); 126 127 if (handlerConfiguration.isEnabled()) 128 { 129 String className = handlerConfiguration.getJavaClass(); 130 try 131 { 132 SASLMechanismHandler handler = loadHandler(className, 133 handlerConfiguration, 134 true); 135 handlers.put(handlerConfiguration.dn(), handler); 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 SASLMechanismHandlerCfg 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 SASL 158 // mechanism handler. 159 String className = configuration.getJavaClass(); 160 try 161 { 162 loadHandler(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 SASLMechanismHandlerCfg 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 SASLMechanismHandler handler = null; 195 196 // Get the name of the class and make sure we can instantiate it as a SASL 197 // mechanism handler. 198 String className = configuration.getJavaClass(); 199 try 200 { 201 handler = loadHandler(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 handlers.put(configuration.dn(), handler); 216 } 217 218 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 219 } 220 221 222 223 /** 224 * {@inheritDoc} 225 */ 226 public boolean isConfigurationDeleteAcceptable( 227 SASLMechanismHandlerCfg configuration, 228 List<Message> unacceptableReasons) 229 { 230 // FIXME -- We should try to perform some check to determine whether the 231 // SASL mechanism handler is in use. 232 return true; 233 } 234 235 236 237 /** 238 * {@inheritDoc} 239 */ 240 public ConfigChangeResult applyConfigurationDelete( 241 SASLMechanismHandlerCfg configuration) 242 { 243 ResultCode resultCode = ResultCode.SUCCESS; 244 boolean adminActionRequired = false; 245 ArrayList<Message> messages = new ArrayList<Message>(); 246 247 SASLMechanismHandler handler = handlers.remove(configuration.dn()); 248 if (handler != null) 249 { 250 handler.finalizeSASLMechanismHandler(); 251 } 252 253 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 254 } 255 256 257 258 /** 259 * {@inheritDoc} 260 */ 261 public boolean isConfigurationChangeAcceptable( 262 SASLMechanismHandlerCfg configuration, 263 List<Message> unacceptableReasons) 264 { 265 if (configuration.isEnabled()) 266 { 267 // Get the name of the class and make sure we can instantiate it as a SASL 268 // mechanism handler. 269 String className = configuration.getJavaClass(); 270 try 271 { 272 loadHandler(className, configuration, false); 273 } 274 catch (InitializationException ie) 275 { 276 unacceptableReasons.add(ie.getMessageObject()); 277 return false; 278 } 279 } 280 281 // If we've gotten here, then it's fine. 282 return true; 283 } 284 285 286 287 /** 288 * {@inheritDoc} 289 */ 290 public ConfigChangeResult applyConfigurationChange( 291 SASLMechanismHandlerCfg configuration) 292 { 293 ResultCode resultCode = ResultCode.SUCCESS; 294 boolean adminActionRequired = false; 295 ArrayList<Message> messages = new ArrayList<Message>(); 296 297 298 // Get the existing handler if it's already enabled. 299 SASLMechanismHandler existingHandler = handlers.get(configuration.dn()); 300 301 302 // If the new configuration has the handler disabled, then disable it if it 303 // is enabled, or do nothing if it's already disabled. 304 if (! configuration.isEnabled()) 305 { 306 if (existingHandler != null) 307 { 308 SASLMechanismHandler handler = handlers.remove(configuration.dn()); 309 if (handler != null) 310 { 311 handler.finalizeSASLMechanismHandler(); 312 } 313 } 314 315 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 316 } 317 318 319 // Get the class for the SASL handler. If the handler is already enabled, 320 // then we shouldn't do anything with it although if the class has changed 321 // then we'll at least need to indicate that administrative action is 322 // required. If the handler is disabled, then instantiate the class and 323 // initialize and register it as a SASL mechanism handler. 324 String className = configuration.getJavaClass(); 325 if (existingHandler != null) 326 { 327 if (! className.equals(existingHandler.getClass().getName())) 328 { 329 adminActionRequired = true; 330 } 331 332 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 333 } 334 335 SASLMechanismHandler handler = null; 336 try 337 { 338 handler = loadHandler(className, configuration, true); 339 } 340 catch (InitializationException ie) 341 { 342 if (resultCode == ResultCode.SUCCESS) 343 { 344 resultCode = DirectoryServer.getServerErrorResultCode(); 345 } 346 347 messages.add(ie.getMessageObject()); 348 } 349 350 if (resultCode == ResultCode.SUCCESS) 351 { 352 handlers.put(configuration.dn(), handler); 353 } 354 355 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 356 } 357 358 359 360 /** 361 * Loads the specified class, instantiates it as a SASL mechanism hanlder, and 362 * optionally initializes that instance. 363 * 364 * @param className The fully-qualified name of the SASL mechanism 365 * handler class to load, instantiate, and initialize. 366 * @param configuration The configuration to use to initialize the handler. 367 * It must not be {@code null}. 368 * @param initialize Indicates whether the SASL mechanism handler 369 * instance should be initialized. 370 * 371 * @return The possibly initialized SASL mechanism handler. 372 * 373 * @throws InitializationException If a problem occurred while attempting to 374 * initialize the SASL mechanism handler. 375 */ 376 private SASLMechanismHandler loadHandler(String className, 377 SASLMechanismHandlerCfg 378 configuration, 379 boolean initialize) 380 throws InitializationException 381 { 382 try 383 { 384 SASLMechanismHandlerCfgDefn definition = 385 SASLMechanismHandlerCfgDefn.getInstance(); 386 ClassPropertyDefinition propertyDefinition = 387 definition.getJavaClassPropertyDefinition(); 388 Class<? extends SASLMechanismHandler> handlerClass = 389 propertyDefinition.loadClass(className, SASLMechanismHandler.class); 390 SASLMechanismHandler handler = handlerClass.newInstance(); 391 392 if (initialize) 393 { 394 Method method = handler.getClass().getMethod( 395 "initializeSASLMechanismHandler", 396 configuration.configurationClass()); 397 method.invoke(handler, configuration); 398 } 399 else 400 { 401 Method method = 402 handler.getClass().getMethod("isConfigurationAcceptable", 403 SASLMechanismHandlerCfg.class, 404 List.class); 405 406 List<Message> unacceptableReasons = new ArrayList<Message>(); 407 Boolean acceptable = (Boolean) method.invoke(handler, configuration, 408 unacceptableReasons); 409 if (! acceptable) 410 { 411 StringBuilder buffer = new StringBuilder(); 412 if (! unacceptableReasons.isEmpty()) 413 { 414 Iterator<Message> iterator = unacceptableReasons.iterator(); 415 buffer.append(iterator.next()); 416 while (iterator.hasNext()) 417 { 418 buffer.append(". "); 419 buffer.append(iterator.next()); 420 } 421 } 422 423 Message message = ERR_CONFIG_SASL_CONFIG_NOT_ACCEPTABLE.get( 424 String.valueOf(configuration.dn()), buffer.toString()); 425 throw new InitializationException(message); 426 } 427 } 428 429 return handler; 430 } 431 catch (Exception e) 432 { 433 Message message = ERR_CONFIG_SASL_INITIALIZATION_FAILED. 434 get(className, String.valueOf(configuration.dn()), 435 stackTraceToSingleLineString(e)); 436 throw new InitializationException(message, e); 437 } 438 } 439 } 440