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 legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS. 026 */ 027package org.opends.server.core; 028 029import java.util.*; 030 031import org.forgerock.i18n.LocalizableMessage; 032import org.forgerock.opendj.config.server.ConfigChangeResult; 033import org.forgerock.opendj.config.server.ConfigException; 034import org.forgerock.opendj.ldap.ResultCode; 035import org.forgerock.opendj.ldap.schema.Schema; 036import org.forgerock.opendj.ldap.schema.SchemaBuilder; 037import org.forgerock.opendj.ldap.schema.SchemaOptions; 038import org.opends.server.admin.server.ConfigurationChangeListener; 039import org.opends.server.admin.server.ServerManagementContext; 040import org.opends.server.admin.std.meta.GlobalCfgDefn; 041import org.opends.server.admin.std.meta.GlobalCfgDefn.DisabledPrivilege; 042import org.opends.server.admin.std.meta.GlobalCfgDefn.InvalidAttributeSyntaxBehavior; 043import org.opends.server.admin.std.meta.GlobalCfgDefn.SingleStructuralObjectclassBehavior; 044import org.opends.server.admin.std.server.GlobalCfg; 045import org.opends.server.admin.std.server.RootCfg; 046import org.opends.server.api.AuthenticationPolicy; 047import org.opends.server.loggers.CommonAudit; 048import org.opends.server.schema.SchemaUpdater; 049import org.opends.server.types.*; 050 051import static org.opends.messages.ConfigMessages.*; 052import static org.opends.server.core.DirectoryServer.*; 053import static org.opends.server.util.ServerConstants.*; 054 055/** 056 * This class defines a utility that will be used to manage the set of core 057 * configuration attributes defined in the Directory Server. These 058 * configuration attributes appear in the "cn=config" configuration entry. 059 */ 060public class CoreConfigManager 061 implements ConfigurationChangeListener<GlobalCfg> 062{ 063 private final ServerContext serverContext; 064 065 /** 066 * Creates a new instance of this core config manager. 067 * 068 * @param serverContext 069 * The server context. 070 */ 071 public CoreConfigManager(ServerContext serverContext) 072 { 073 this.serverContext = serverContext; 074 } 075 076 /** 077 * Initializes the Directory Server's core configuration. This should only be 078 * called at server startup. 079 * 080 * @throws ConfigException 081 * If a configuration problem causes the identity mapper 082 * initialization process to fail. 083 * @throws InitializationException 084 * If a problem occurs while initializing the identity mappers that 085 * is not related to the server configuration. 086 */ 087 public void initializeCoreConfig() 088 throws ConfigException, InitializationException 089 { 090 // Get the root configuration object. 091 ServerManagementContext managementContext = 092 ServerManagementContext.getInstance(); 093 RootCfg rootConfiguration = 094 managementContext.getRootConfiguration(); 095 096 097 // Get the global configuration and register with it as a change listener. 098 GlobalCfg globalConfig = rootConfiguration.getGlobalConfiguration(); 099 globalConfig.addChangeListener(this); 100 101 102 // If there are any STMP servers specified, then make sure that if the value 103 // contains a colon that the portion after it is an integer between 1 and 104 // 65535. 105 Set<String> smtpServers = globalConfig.getSMTPServer(); 106 if (smtpServers != null) 107 { 108 for (String server : smtpServers) 109 { 110 try 111 { 112 // validate provided string 113 HostPort.valueOf(server); 114 } 115 catch (RuntimeException e) 116 { 117 LocalizableMessage message = ERR_CONFIG_CORE_INVALID_SMTP_SERVER.get(server); 118 throw new ConfigException(message, e); 119 } 120 } 121 } 122 123 124 // Apply the configuration to the server. 125 applyGlobalConfiguration(globalConfig, serverContext); 126 } 127 128 129 130 /** 131 * Applies the settings in the provided configuration to the Directory Server. 132 * 133 * @param globalConfig The configuration settings to be applied. 134 */ 135 private static void applyGlobalConfiguration(GlobalCfg globalConfig, ServerContext serverContext) 136 { 137 setCheckSchema(globalConfig.isCheckSchema()); 138 setDefaultPasswordPolicyDN(globalConfig.getDefaultPasswordPolicyDN()); 139 setAddMissingRDNAttributes(globalConfig.isAddMissingRDNAttributes()); 140 setAllowAttributeNameExceptions(globalConfig.isAllowAttributeNameExceptions()); 141 setSyntaxEnforcementPolicy(convert(globalConfig.getInvalidAttributeSyntaxBehavior())); 142 setServerErrorResultCode(ResultCode.valueOf(globalConfig.getServerErrorResultCode())); 143 setSingleStructuralObjectClassPolicy(convert(globalConfig.getSingleStructuralObjectclassBehavior())); 144 145 setNotifyAbandonedOperations(globalConfig.isNotifyAbandonedOperations()); 146 setSizeLimit(globalConfig.getSizeLimit()); 147 setTimeLimit((int) globalConfig.getTimeLimit()); 148 setProxiedAuthorizationIdentityMapperDN(globalConfig.getProxiedAuthorizationIdentityMapperDN()); 149 setWritabilityMode(convert(globalConfig.getWritabilityMode())); 150 setRejectUnauthenticatedRequests(globalConfig.isRejectUnauthenticatedRequests()); 151 setBindWithDNRequiresPassword(globalConfig.isBindWithDNRequiresPassword()); 152 setLookthroughLimit(globalConfig.getLookthroughLimit()); 153 154 setMailServerPropertySets(getMailServerProperties(globalConfig.getSMTPServer())); 155 setAllowedTasks(globalConfig.getAllowedTask()); 156 setDisabledPrivileges(convert(globalConfig.getDisabledPrivilege())); 157 setReturnBindErrorMessages(globalConfig.isReturnBindErrorMessages()); 158 setIdleTimeLimit(globalConfig.getIdleTimeLimit()); 159 setSaveConfigOnSuccessfulStartup(globalConfig.isSaveConfigOnSuccessfulStartup()); 160 161 setUseNanoTime(globalConfig.getEtimeResolution() == GlobalCfgDefn.EtimeResolution.NANOSECONDS); 162 setMaxAllowedConnections(globalConfig.getMaxAllowedClientConnections()); 163 setMaxPersistentSearchLimit(globalConfig.getMaxPsearches()); 164 setMaxInternalBufferSize((int) globalConfig.getMaxInternalBufferSize()); 165 166 // For tools, common audit may not be available 167 CommonAudit commonAudit = serverContext.getCommonAudit(); 168 if (commonAudit != null) 169 { 170 commonAudit.setTrustTransactionIds(globalConfig.isTrustTransactionIds()); 171 } 172 173 // Update the "new" schema with configuration changes 174 SchemaUpdater schemaUpdater = serverContext.getSchemaUpdater(); 175 SchemaBuilder schemaBuilder = schemaUpdater.getSchemaBuilder(); 176 boolean allowMalformedNames = globalConfig.isAllowAttributeNameExceptions(); 177 schemaBuilder.setOption(SchemaOptions.ALLOW_MALFORMED_NAMES_AND_OPTIONS, allowMalformedNames); 178 Schema schema = schemaBuilder.toSchema(); 179 if (!globalConfig.isCheckSchema()) 180 { 181 schema = schema.asNonStrictSchema(); 182 } 183 schemaUpdater.updateSchema(schema); 184 } 185 186 private static AcceptRejectWarn convert(InvalidAttributeSyntaxBehavior invalidAttributeSyntaxBehavior) 187 { 188 switch (invalidAttributeSyntaxBehavior) 189 { 190 case ACCEPT: 191 return AcceptRejectWarn.ACCEPT; 192 case WARN: 193 return AcceptRejectWarn.WARN; 194 case REJECT: 195 default: 196 return AcceptRejectWarn.REJECT; 197 } 198 } 199 200 private static AcceptRejectWarn convert(SingleStructuralObjectclassBehavior singleStructuralObjectclassBehavior) 201 { 202 switch (singleStructuralObjectclassBehavior) 203 { 204 case ACCEPT: 205 return AcceptRejectWarn.ACCEPT; 206 case WARN: 207 return AcceptRejectWarn.WARN; 208 case REJECT: 209 default: 210 return AcceptRejectWarn.REJECT; 211 } 212 } 213 214 private static WritabilityMode convert(GlobalCfgDefn.WritabilityMode writabilityMode) 215 { 216 switch (writabilityMode) 217 { 218 case ENABLED: 219 return WritabilityMode.ENABLED; 220 case INTERNAL_ONLY: 221 return WritabilityMode.INTERNAL_ONLY; 222 case DISABLED: 223 default: 224 return WritabilityMode.DISABLED; 225 } 226 } 227 228 private static List<Properties> getMailServerProperties(Set<String> smtpServers) 229 { 230 List<Properties> mailServerProperties = new ArrayList<>(); 231 if (smtpServers != null && !smtpServers.isEmpty()) 232 { 233 for (String smtpServer : smtpServers) 234 { 235 final Properties properties = new Properties(); 236 try 237 { 238 final HostPort hp = HostPort.valueOf(smtpServer); 239 240 properties.setProperty(SMTP_PROPERTY_HOST, hp.getHost()); 241 properties.setProperty(SMTP_PROPERTY_PORT, 242 String.valueOf(hp.getPort())); 243 properties.setProperty(SMTP_PROPERTY_CONNECTION_TIMEOUT, 244 SMTP_DEFAULT_TIMEOUT_VALUE); 245 properties.setProperty(SMTP_PROPERTY_IO_TIMEOUT, 246 SMTP_DEFAULT_TIMEOUT_VALUE); 247 } 248 catch (RuntimeException e) 249 { 250 // no valid port provided 251 properties.setProperty(SMTP_PROPERTY_HOST, smtpServer); 252 } 253 mailServerProperties.add(properties); 254 } 255 } 256 return mailServerProperties; 257 } 258 259 private static HashSet<Privilege> convert(Set<DisabledPrivilege> configuredDisabledPrivs) 260 { 261 HashSet<Privilege> disabledPrivileges = new HashSet<>(); 262 if (configuredDisabledPrivs != null) 263 { 264 for (DisabledPrivilege p : configuredDisabledPrivs) 265 { 266 final Privilege privilege = convert(p); 267 if (privilege != null) 268 { 269 disabledPrivileges.add(privilege); 270 } 271 } 272 } 273 return disabledPrivileges; 274 } 275 276 private static Privilege convert(DisabledPrivilege privilege) 277 { 278 switch (privilege) 279 { 280 case BACKEND_BACKUP: 281 return Privilege.BACKEND_BACKUP; 282 case BACKEND_RESTORE: 283 return Privilege.BACKEND_RESTORE; 284 case BYPASS_ACL: 285 return Privilege.BYPASS_ACL; 286 case CANCEL_REQUEST: 287 return Privilege.CANCEL_REQUEST; 288 case CONFIG_READ: 289 return Privilege.CONFIG_READ; 290 case CONFIG_WRITE: 291 return Privilege.CONFIG_WRITE; 292 case DATA_SYNC: 293 return Privilege.DATA_SYNC; 294 case DISCONNECT_CLIENT: 295 return Privilege.DISCONNECT_CLIENT; 296 case JMX_NOTIFY: 297 return Privilege.JMX_NOTIFY; 298 case JMX_READ: 299 return Privilege.JMX_READ; 300 case JMX_WRITE: 301 return Privilege.JMX_WRITE; 302 case LDIF_EXPORT: 303 return Privilege.LDIF_EXPORT; 304 case LDIF_IMPORT: 305 return Privilege.LDIF_IMPORT; 306 case MODIFY_ACL: 307 return Privilege.MODIFY_ACL; 308 case PASSWORD_RESET: 309 return Privilege.PASSWORD_RESET; 310 case PRIVILEGE_CHANGE: 311 return Privilege.PRIVILEGE_CHANGE; 312 case PROXIED_AUTH: 313 return Privilege.PROXIED_AUTH; 314 case SERVER_RESTART: 315 return Privilege.SERVER_RESTART; 316 case SERVER_SHUTDOWN: 317 return Privilege.SERVER_SHUTDOWN; 318 case UNINDEXED_SEARCH: 319 return Privilege.UNINDEXED_SEARCH; 320 case UPDATE_SCHEMA: 321 return Privilege.UPDATE_SCHEMA; 322 case SUBENTRY_WRITE: 323 return Privilege.SUBENTRY_WRITE; 324 default: 325 return null; 326 } 327 } 328 329 330 /** {@inheritDoc} */ 331 @Override 332 public boolean isConfigurationChangeAcceptable(GlobalCfg configuration, 333 List<LocalizableMessage> unacceptableReasons) 334 { 335 boolean configAcceptable = true; 336 337 Set<String> smtpServers = configuration.getSMTPServer(); 338 if (smtpServers != null) 339 { 340 for (String server : smtpServers) 341 { 342 try 343 { 344 // validate provided string 345 HostPort.valueOf(server); 346 } 347 catch (RuntimeException e) 348 { 349 LocalizableMessage message = ERR_CONFIG_CORE_INVALID_SMTP_SERVER.get(server); 350 unacceptableReasons.add(message); 351 configAcceptable = false; 352 } 353 } 354 } 355 356 // Ensure that the default password policy always points to a password 357 // policy and not another type of authentication policy. 358 DN defaultPasswordPolicyDN = configuration.getDefaultPasswordPolicyDN(); 359 AuthenticationPolicy policy = DirectoryServer 360 .getAuthenticationPolicy(defaultPasswordPolicyDN); 361 if (!policy.isPasswordPolicy()) 362 { 363 LocalizableMessage message = 364 ERR_CONFIG_PWPOLICY_CANNOT_CHANGE_DEFAULT_POLICY_WRONG_TYPE 365 .get(configuration.getDefaultPasswordPolicy()); 366 unacceptableReasons.add(message); 367 configAcceptable = false; 368 } 369 370 return configAcceptable; 371 } 372 373 374 375 /** {@inheritDoc} */ 376 @Override 377 public ConfigChangeResult applyConfigurationChange(GlobalCfg configuration) 378 { 379 final ConfigChangeResult ccr = new ConfigChangeResult(); 380 381 applyGlobalConfiguration(configuration, serverContext); 382 383 return ccr; 384 } 385} 386