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