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 static org.opends.messages.ConfigMessages.*; 020import static org.opends.server.util.StaticUtils.*; 021 022import java.util.ArrayList; 023import java.util.List; 024import java.util.concurrent.ConcurrentHashMap; 025 026import org.forgerock.i18n.LocalizableMessage; 027import org.forgerock.i18n.slf4j.LocalizedLogger; 028import org.forgerock.opendj.config.server.ConfigException; 029import org.forgerock.opendj.ldap.ResultCode; 030import org.forgerock.util.Utils; 031import org.forgerock.opendj.config.ClassPropertyDefinition; 032import org.forgerock.opendj.config.server.ConfigurationAddListener; 033import org.forgerock.opendj.config.server.ConfigurationChangeListener; 034import org.forgerock.opendj.config.server.ConfigurationDeleteListener; 035import org.forgerock.opendj.server.config.meta.SASLMechanismHandlerCfgDefn; 036import org.forgerock.opendj.server.config.server.RootCfg; 037import org.forgerock.opendj.server.config.server.SASLMechanismHandlerCfg; 038import org.opends.server.api.SASLMechanismHandler; 039import org.forgerock.opendj.config.server.ConfigChangeResult; 040import org.forgerock.opendj.ldap.DN; 041import org.opends.server.types.InitializationException; 042 043/** 044 * This class defines a utility that will be used to manage the set of SASL 045 * mechanism handlers defined in the Directory Server. It will initialize the 046 * handlers when the server starts, and then will manage any additions, 047 * removals, or modifications to any SASL mechanism handlers while the server is 048 * running. 049 */ 050public class SASLConfigManager implements 051 ConfigurationChangeListener<SASLMechanismHandlerCfg>, 052 ConfigurationAddListener<SASLMechanismHandlerCfg>, 053 ConfigurationDeleteListener<SASLMechanismHandlerCfg> 054{ 055 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 056 057 /** A mapping between the DNs of the config entries and the associated SASL mechanism handlers. */ 058 private final ConcurrentHashMap<DN, SASLMechanismHandler> handlers; 059 060 private final ServerContext serverContext; 061 062 /** 063 * Creates a new instance of this SASL mechanism handler config manager. 064 * 065 * @param serverContext 066 * The server context. 067 */ 068 public SASLConfigManager(ServerContext serverContext) 069 { 070 this.serverContext = serverContext; 071 handlers = new ConcurrentHashMap<>(); 072 } 073 074 /** 075 * Initializes all SASL mechanism handlers currently defined in the Directory 076 * Server configuration. This should only be called at Directory Server 077 * startup. 078 * 079 * @throws ConfigException If a configuration problem causes the SASL 080 * mechanism handler initialization process to fail. 081 * 082 * @throws InitializationException If a problem occurs while initializing 083 * the SASL mechanism handlers that is not 084 * related to the server configuration. 085 */ 086 public void initializeSASLMechanismHandlers() 087 throws ConfigException, InitializationException 088 { 089 RootCfg rootConfiguration = serverContext.getRootConfig(); 090 rootConfiguration.addSASLMechanismHandlerAddListener(this); 091 rootConfiguration.addSASLMechanismHandlerDeleteListener(this); 092 093 //Initialize the existing SASL mechanism handlers. 094 for (String handlerName : rootConfiguration.listSASLMechanismHandlers()) 095 { 096 SASLMechanismHandlerCfg handlerConfiguration = 097 rootConfiguration.getSASLMechanismHandler(handlerName); 098 handlerConfiguration.addChangeListener(this); 099 100 if (handlerConfiguration.isEnabled()) 101 { 102 String className = handlerConfiguration.getJavaClass(); 103 try 104 { 105 SASLMechanismHandler handler = loadHandler(className, 106 handlerConfiguration, 107 true); 108 handlers.put(handlerConfiguration.dn(), handler); 109 } 110 catch (InitializationException ie) 111 { 112 logger.error(ie.getMessageObject()); 113 continue; 114 } 115 } 116 } 117 } 118 119 @Override 120 public boolean isConfigurationAddAcceptable( 121 SASLMechanismHandlerCfg configuration, 122 List<LocalizableMessage> unacceptableReasons) 123 { 124 if (configuration.isEnabled()) 125 { 126 // Get the name of the class and make sure we can instantiate it as a SASL 127 // mechanism handler. 128 String className = configuration.getJavaClass(); 129 try 130 { 131 loadHandler(className, configuration, false); 132 } 133 catch (InitializationException ie) 134 { 135 unacceptableReasons.add(ie.getMessageObject()); 136 return false; 137 } 138 } 139 140 // If we've gotten here, then it's fine. 141 return true; 142 } 143 144 @Override 145 public ConfigChangeResult applyConfigurationAdd( 146 SASLMechanismHandlerCfg configuration) 147 { 148 final ConfigChangeResult ccr = new ConfigChangeResult(); 149 150 configuration.addChangeListener(this); 151 152 if (! configuration.isEnabled()) 153 { 154 return ccr; 155 } 156 157 SASLMechanismHandler handler = null; 158 159 // Get the name of the class and make sure we can instantiate it as a SASL 160 // mechanism handler. 161 String className = configuration.getJavaClass(); 162 try 163 { 164 handler = loadHandler(className, configuration, true); 165 } 166 catch (InitializationException ie) 167 { 168 ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode()); 169 ccr.addMessage(ie.getMessageObject()); 170 } 171 172 if (ccr.getResultCode() == ResultCode.SUCCESS) 173 { 174 handlers.put(configuration.dn(), handler); 175 } 176 177 return ccr; 178 } 179 180 @Override 181 public boolean isConfigurationDeleteAcceptable( 182 SASLMechanismHandlerCfg configuration, 183 List<LocalizableMessage> unacceptableReasons) 184 { 185 // FIXME -- We should try to perform some check to determine whether the 186 // SASL mechanism handler is in use. 187 return true; 188 } 189 190 @Override 191 public ConfigChangeResult applyConfigurationDelete( 192 SASLMechanismHandlerCfg configuration) 193 { 194 final ConfigChangeResult ccr = new ConfigChangeResult(); 195 196 SASLMechanismHandler handler = handlers.remove(configuration.dn()); 197 if (handler != null) 198 { 199 handler.finalizeSASLMechanismHandler(); 200 } 201 202 return ccr; 203 } 204 205 @Override 206 public boolean isConfigurationChangeAcceptable( 207 SASLMechanismHandlerCfg configuration, 208 List<LocalizableMessage> unacceptableReasons) 209 { 210 if (configuration.isEnabled()) 211 { 212 // Get the name of the class and make sure we can instantiate it as a SASL 213 // mechanism handler. 214 String className = configuration.getJavaClass(); 215 try 216 { 217 loadHandler(className, configuration, false); 218 } 219 catch (InitializationException ie) 220 { 221 unacceptableReasons.add(ie.getMessageObject()); 222 return false; 223 } 224 } 225 226 // If we've gotten here, then it's fine. 227 return true; 228 } 229 230 @Override 231 public ConfigChangeResult applyConfigurationChange( 232 SASLMechanismHandlerCfg configuration) 233 { 234 final ConfigChangeResult ccr = new ConfigChangeResult(); 235 236 // Get the existing handler if it's already enabled. 237 SASLMechanismHandler existingHandler = handlers.get(configuration.dn()); 238 239 // If the new configuration has the handler disabled, then disable it if it 240 // is enabled, or do nothing if it's already disabled. 241 if (! configuration.isEnabled()) 242 { 243 if (existingHandler != null) 244 { 245 SASLMechanismHandler handler = handlers.remove(configuration.dn()); 246 if (handler != null) 247 { 248 handler.finalizeSASLMechanismHandler(); 249 } 250 } 251 252 return ccr; 253 } 254 255 // Get the class for the SASL handler. If the handler is already enabled, 256 // then we shouldn't do anything with it although if the class has changed 257 // then we'll at least need to indicate that administrative action is 258 // required. If the handler is disabled, then instantiate the class and 259 // initialize and register it as a SASL mechanism handler. 260 String className = configuration.getJavaClass(); 261 if (existingHandler != null) 262 { 263 if (! className.equals(existingHandler.getClass().getName())) 264 { 265 ccr.setAdminActionRequired(true); 266 } 267 268 return ccr; 269 } 270 271 SASLMechanismHandler handler = null; 272 try 273 { 274 handler = loadHandler(className, configuration, true); 275 } 276 catch (InitializationException ie) 277 { 278 ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode()); 279 ccr.addMessage(ie.getMessageObject()); 280 } 281 282 if (ccr.getResultCode() == ResultCode.SUCCESS) 283 { 284 handlers.put(configuration.dn(), handler); 285 } 286 287 return ccr; 288 } 289 290 /** 291 * Loads the specified class, instantiates it as a SASL mechanism hanlder, and 292 * optionally initializes that instance. 293 * 294 * @param className The fully-qualified name of the SASL mechanism 295 * handler class to load, instantiate, and initialize. 296 * @param configuration The configuration to use to initialize the handler. 297 * It must not be {@code null}. 298 * @param initialize Indicates whether the SASL mechanism handler 299 * instance should be initialized. 300 * 301 * @return The possibly initialized SASL mechanism handler. 302 * 303 * @throws InitializationException If a problem occurred while attempting to 304 * initialize the SASL mechanism handler. 305 */ 306 private SASLMechanismHandler loadHandler(String className, 307 SASLMechanismHandlerCfg 308 configuration, 309 boolean initialize) 310 throws InitializationException 311 { 312 try 313 { 314 SASLMechanismHandlerCfgDefn definition = 315 SASLMechanismHandlerCfgDefn.getInstance(); 316 ClassPropertyDefinition propertyDefinition = 317 definition.getJavaClassPropertyDefinition(); 318 Class<? extends SASLMechanismHandler> handlerClass = 319 propertyDefinition.loadClass(className, SASLMechanismHandler.class); 320 SASLMechanismHandler handler = handlerClass.newInstance(); 321 322 if (initialize) 323 { 324 handler.initializeSASLMechanismHandler(configuration); 325 } 326 else 327 { 328 List<LocalizableMessage> unacceptableReasons = new ArrayList<>(); 329 if (!handler.isConfigurationAcceptable(configuration, unacceptableReasons)) 330 { 331 String reasons = Utils.joinAsString(". ", unacceptableReasons); 332 throw new InitializationException( 333 ERR_CONFIG_SASL_CONFIG_NOT_ACCEPTABLE.get(configuration.dn(), reasons)); 334 } 335 } 336 337 return handler; 338 } 339 catch (Exception e) 340 { 341 LocalizableMessage message = ERR_CONFIG_SASL_INITIALIZATION_FAILED. 342 get(className, configuration.dn(), stackTraceToSingleLineString(e)); 343 throw new InitializationException(message, e); 344 } 345 } 346}