2372N/A/*
2372N/A * CDDL HEADER START
2372N/A *
2372N/A * The contents of this file are subject to the terms of the
2372N/A * Common Development and Distribution License, Version 1.0 only
2372N/A * (the "License"). You may not use this file except in compliance
2372N/A * with the License.
2372N/A *
2372N/A * You can obtain a copy of the license at
2372N/A * trunk/opends/resource/legal-notices/OpenDS.LICENSE
2372N/A * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
2372N/A * See the License for the specific language governing permissions
2372N/A * and limitations under the License.
2372N/A *
2372N/A * When distributing Covered Code, include this CDDL HEADER in each
2372N/A * file and include the License file at
2372N/A * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
2372N/A * add the following below this CDDL HEADER, with the fields enclosed
2372N/A * by brackets "[]" replaced with your own identifying information:
2372N/A * Portions Copyright [yyyy] [name of copyright owner]
2372N/A *
2372N/A * CDDL HEADER END
2372N/A *
2372N/A *
3215N/A * Copyright 2008 Sun Microsystems, Inc.
2372N/A */
2372N/Apackage org.opends.server.plugins;
2372N/A
2372N/A
2372N/A
2372N/Aimport java.util.List;
2372N/Aimport java.util.Set;
2372N/A
2372N/Aimport org.opends.messages.Message;
2372N/Aimport org.opends.server.admin.server.ConfigurationChangeListener;
2372N/Aimport org.opends.server.admin.std.meta.PluginCfgDefn;
2372N/Aimport org.opends.server.admin.std.server.SevenBitCleanPluginCfg;
2372N/Aimport org.opends.server.admin.std.server.PluginCfg;
3352N/Aimport org.opends.server.api.plugin.*;
2372N/Aimport org.opends.server.config.ConfigException;
2372N/Aimport org.opends.server.core.DirectoryServer;
4134N/Aimport org.opends.server.types.*;
2372N/Aimport org.opends.server.types.operation.PreParseAddOperation;
2372N/Aimport org.opends.server.types.operation.PreParseModifyOperation;
2372N/Aimport org.opends.server.types.operation.PreParseModifyDNOperation;
2372N/A
2372N/Aimport static org.opends.messages.PluginMessages.*;
2372N/A
2372N/A
2372N/A
2372N/A/**
2372N/A * This class implements a Directory Server plugin that can be used to ensure
2372N/A * that the values for a specified set of attributes (optionally, below a
2372N/A * specified set of base DNs) are 7-bit clean (i.e., contain only ASCII
2372N/A * characters).
2372N/A */
2372N/Apublic final class SevenBitCleanPlugin
2372N/A extends DirectoryServerPlugin<SevenBitCleanPluginCfg>
2372N/A implements ConfigurationChangeListener<SevenBitCleanPluginCfg>
2372N/A{
2372N/A /**
2372N/A * The bitmask that will be used to make the comparisons.
2372N/A */
2372N/A private static final byte MASK = (byte) 0x7F;
2372N/A
2372N/A
2372N/A
2372N/A // The current configuration for this plugin.
2372N/A private SevenBitCleanPluginCfg currentConfig;
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * Creates a new instance of this Directory Server plugin. Every plugin must
2372N/A * implement a default constructor (it is the only one that will be used to
2372N/A * create plugins defined in the configuration), and every plugin constructor
2372N/A * must call {@code super()} as its first element.
2372N/A */
2372N/A public SevenBitCleanPlugin()
2372N/A {
2372N/A super();
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * {@inheritDoc}
2372N/A */
2372N/A @Override()
2372N/A public final void initializePlugin(Set<PluginType> pluginTypes,
2372N/A SevenBitCleanPluginCfg configuration)
2372N/A throws ConfigException
2372N/A {
2372N/A currentConfig = configuration;
2372N/A configuration.addSevenBitCleanChangeListener(this);
2372N/A
2372N/A // Make sure that the plugin has been enabled for the appropriate types.
2372N/A for (PluginType t : pluginTypes)
2372N/A {
2372N/A switch (t)
2372N/A {
2372N/A case LDIF_IMPORT:
2372N/A case PRE_PARSE_ADD:
2372N/A case PRE_PARSE_MODIFY:
2372N/A case PRE_PARSE_MODIFY_DN:
2372N/A // These are acceptable.
2372N/A break;
2372N/A
2372N/A
2372N/A default:
2372N/A Message message =
2372N/A ERR_PLUGIN_7BIT_INVALID_PLUGIN_TYPE.get(t.toString());
2372N/A throw new ConfigException(message);
2372N/A }
2372N/A }
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * {@inheritDoc}
2372N/A */
2372N/A @Override()
2372N/A public final void finalizePlugin()
2372N/A {
2372N/A currentConfig.removeSevenBitCleanChangeListener(this);
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * {@inheritDoc}
2372N/A */
2372N/A @Override()
3352N/A public final PluginResult.ImportLDIF
3352N/A doLDIFImport(LDIFImportConfig importConfig, Entry entry)
2372N/A {
2372N/A // Get the current configuration for this plugin.
2372N/A SevenBitCleanPluginCfg config = currentConfig;
2372N/A
2372N/A
2372N/A // Make sure that the entry is within the scope of this plugin. While
2372N/A // processing an LDIF import, we don't have access to the set of public
2372N/A // naming contexts defined in the server, so if no explicit set of base DNs
2372N/A // is defined, then assume that the entry is in scope.
2372N/A Set<DN> baseDNs = config.getBaseDN();
2372N/A if ((baseDNs != null) && (! baseDNs.isEmpty()))
2372N/A {
2372N/A boolean found = true;
2372N/A for (DN baseDN : baseDNs)
2372N/A {
2372N/A if (baseDN.isAncestorOf(entry.getDN()))
2372N/A {
2372N/A found = true;
2372N/A break;
2372N/A }
2372N/A }
2372N/A
2372N/A if (! found)
2372N/A {
2372N/A // The entry is out of scope, so we won't process it.
3352N/A return PluginResult.ImportLDIF.continueEntryProcessing();
2372N/A }
2372N/A }
2372N/A
2372N/A
2372N/A // Make sure all configured attributes have clean values.
2372N/A for (AttributeType t : config.getAttributeType())
2372N/A {
2372N/A List<Attribute> attrList = entry.getAttribute(t);
2372N/A if (attrList != null)
2372N/A {
2372N/A for (Attribute a : attrList)
2372N/A {
3853N/A for (AttributeValue v : a)
2372N/A {
2372N/A if (! is7BitClean(v.getValue()))
2372N/A {
2373N/A Message rejectMessage =
2373N/A ERR_PLUGIN_7BIT_IMPORT_ATTR_NOT_CLEAN.get(
2373N/A a.getNameWithOptions());
3352N/A return PluginResult.ImportLDIF.stopEntryProcessing(rejectMessage);
2372N/A }
2372N/A }
2372N/A }
2372N/A }
2372N/A }
2372N/A
2372N/A
2372N/A // If we've gotten here, then everything is acceptable.
3352N/A return PluginResult.ImportLDIF.continueEntryProcessing();
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * {@inheritDoc}
2372N/A */
2372N/A @Override()
3352N/A public final PluginResult.PreParse
3352N/A doPreParse(PreParseAddOperation addOperation)
2372N/A {
2372N/A // Get the current configuration for this plugin.
2372N/A SevenBitCleanPluginCfg config = currentConfig;
2372N/A
2372N/A
2372N/A // If the entry is within the scope of this plugin, then make sure all
2372N/A // configured attributes have clean values.
2372N/A DN entryDN;
2372N/A try
2372N/A {
2372N/A entryDN = DN.decode(addOperation.getRawEntryDN());
2372N/A }
2372N/A catch (DirectoryException de)
2372N/A {
3352N/A return PluginResult.PreParse.stopProcessing(de.getResultCode(),
3352N/A ERR_PLUGIN_7BIT_CANNOT_DECODE_DN.get(de.getMessageObject()));
2372N/A }
2372N/A
2372N/A if (isInScope(config, entryDN))
2372N/A {
2372N/A for (RawAttribute rawAttr : addOperation.getRawAttributes())
2372N/A {
2372N/A Attribute a;
2372N/A try
2372N/A {
2372N/A a = rawAttr.toAttribute();
2372N/A }
2372N/A catch (LDAPException le)
2372N/A {
3352N/A return PluginResult.PreParse.stopProcessing(
3352N/A ResultCode.valueOf(le.getResultCode()),
3352N/A ERR_PLUGIN_7BIT_CANNOT_DECODE_ATTR.get(
3352N/A rawAttr.getAttributeType(), le.getErrorMessage()));
2372N/A }
2372N/A
2372N/A if (! config.getAttributeType().contains(a.getAttributeType()))
2372N/A {
2372N/A continue;
2372N/A }
2372N/A
3853N/A for (AttributeValue v : a)
2372N/A {
2372N/A if (! is7BitClean(v.getValue()))
2372N/A {
3352N/A return PluginResult.PreParse.stopProcessing(
3352N/A ResultCode.CONSTRAINT_VIOLATION,
3352N/A ERR_PLUGIN_7BIT_MODIFYDN_ATTR_NOT_CLEAN.get(
3352N/A rawAttr.getAttributeType()));
2372N/A }
2372N/A }
2372N/A }
2372N/A }
2372N/A
2372N/A
2372N/A // If we've gotten here, then everything is acceptable.
3352N/A return PluginResult.PreParse.continueOperationProcessing();
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * {@inheritDoc}
2372N/A */
2372N/A @Override()
3352N/A public final PluginResult.PreParse
2372N/A doPreParse(PreParseModifyOperation modifyOperation)
2372N/A {
2372N/A // Get the current configuration for this plugin.
2372N/A SevenBitCleanPluginCfg config = currentConfig;
2372N/A
2372N/A
2372N/A // If the target entry is within the scope of this plugin, then make sure
2372N/A // all values that will be added during the modification will be acceptable.
2372N/A DN entryDN;
2372N/A try
2372N/A {
2372N/A entryDN = DN.decode(modifyOperation.getRawEntryDN());
2372N/A }
2372N/A catch (DirectoryException de)
2372N/A {
3352N/A return PluginResult.PreParse.stopProcessing(de.getResultCode(),
3352N/A ERR_PLUGIN_7BIT_CANNOT_DECODE_DN.get(de.getMessageObject()));
2372N/A }
2372N/A
2372N/A if (isInScope(config, entryDN))
2372N/A {
2372N/A for (RawModification m : modifyOperation.getRawModifications())
2372N/A {
2372N/A switch (m.getModificationType())
2372N/A {
2372N/A case ADD:
2372N/A case REPLACE:
2372N/A // These are modification types that we will process.
2372N/A break;
2372N/A default:
2372N/A // This is not a modifiation type that we will process.
2372N/A continue;
2372N/A }
2372N/A
2372N/A RawAttribute rawAttr = m.getAttribute();
2372N/A Attribute a;
2372N/A try
2372N/A {
2372N/A a = rawAttr.toAttribute();
2372N/A }
2372N/A catch (LDAPException le)
2372N/A {
3352N/A return PluginResult.PreParse.stopProcessing(
3352N/A ResultCode.valueOf(le.getResultCode()),
3352N/A ERR_PLUGIN_7BIT_CANNOT_DECODE_ATTR.get(
3352N/A rawAttr.getAttributeType(), le.getErrorMessage()));
2372N/A }
2372N/A
2372N/A if (! config.getAttributeType().contains(a.getAttributeType()))
2372N/A {
2372N/A continue;
2372N/A }
2372N/A
3853N/A for (AttributeValue v : a)
2372N/A {
2372N/A if (! is7BitClean(v.getValue()))
2372N/A {
3352N/A return PluginResult.PreParse.stopProcessing(
3352N/A ResultCode.CONSTRAINT_VIOLATION,
3352N/A ERR_PLUGIN_7BIT_MODIFYDN_ATTR_NOT_CLEAN.get(
3352N/A rawAttr.getAttributeType()));
2372N/A }
2372N/A }
2372N/A }
2372N/A }
2372N/A
2372N/A
2372N/A // If we've gotten here, then everything is acceptable.
3352N/A return PluginResult.PreParse.continueOperationProcessing();
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * {@inheritDoc}
2372N/A */
2372N/A @Override()
3352N/A public final PluginResult.PreParse
2372N/A doPreParse(PreParseModifyDNOperation modifyDNOperation)
2372N/A {
2372N/A // Get the current configuration for this plugin.
2372N/A SevenBitCleanPluginCfg config = currentConfig;
2372N/A
2372N/A
2372N/A // If the target entry is within the scope of this plugin, then make sure
2372N/A // all values that will be added during the modification will be acceptable.
2372N/A DN entryDN;
2372N/A try
2372N/A {
2372N/A entryDN = DN.decode(modifyDNOperation.getRawEntryDN());
2372N/A }
2372N/A catch (DirectoryException de)
2372N/A {
3352N/A return PluginResult.PreParse.stopProcessing(de.getResultCode(),
3352N/A ERR_PLUGIN_7BIT_CANNOT_DECODE_DN.get(de.getMessageObject()));
2372N/A }
2372N/A
2372N/A if (isInScope(config, entryDN))
2372N/A {
2372N/A ByteString rawNewRDN = modifyDNOperation.getRawNewRDN();
2372N/A
2372N/A RDN newRDN;
2372N/A try
2372N/A {
4134N/A newRDN = RDN.decode(rawNewRDN.toString());
2372N/A }
2372N/A catch (DirectoryException de)
2372N/A {
3352N/A return PluginResult.PreParse.stopProcessing(de.getResultCode(),
3352N/A ERR_PLUGIN_7BIT_CANNOT_DECODE_NEW_RDN.get(de.getMessageObject()));
2372N/A }
2372N/A
2372N/A int numValues = newRDN.getNumValues();
2372N/A for (int i=0; i < numValues; i++)
2372N/A {
2372N/A if (! config.getAttributeType().contains(newRDN.getAttributeType(i)))
2372N/A {
2372N/A continue;
2372N/A }
2372N/A
2372N/A if (! is7BitClean(newRDN.getAttributeValue(i).getValue()))
2372N/A {
3352N/A return PluginResult.PreParse.stopProcessing(
3352N/A ResultCode.CONSTRAINT_VIOLATION,
3352N/A ERR_PLUGIN_7BIT_MODIFYDN_ATTR_NOT_CLEAN.get(
3352N/A newRDN.getAttributeName(i)));
2372N/A }
2372N/A }
2372N/A }
2372N/A
2372N/A
2372N/A // If we've gotten here, then everything is acceptable.
3352N/A return PluginResult.PreParse.continueOperationProcessing();
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * Indicates whether the provided DN is within the scope of this plugin.
2372N/A *
2372N/A * @param config The configuration to use when making the determination.
2372N/A * @param dn The DN for which to make the determination.
2372N/A *
2372N/A * @return {@code true} if the provided DN is within the scope of this
2372N/A * plugin, or {@code false} if not.
2372N/A */
2372N/A private final boolean isInScope(SevenBitCleanPluginCfg config, DN dn)
2372N/A {
2372N/A Set<DN> baseDNs = config.getBaseDN();
2372N/A if ((baseDNs == null) || baseDNs.isEmpty())
2372N/A {
2372N/A baseDNs = DirectoryServer.getPublicNamingContexts().keySet();
2372N/A }
2372N/A
2372N/A boolean found = false;
2372N/A for (DN baseDN: baseDNs)
2372N/A {
2372N/A if (dn.isDescendantOf(baseDN))
2372N/A {
2372N/A found = true;
2372N/A break;
2372N/A }
2372N/A }
2372N/A
2372N/A return found;
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * Indicates whether the provided value is 7-bit clean.
2372N/A *
2372N/A * @param value The value for which to make the determination.
2372N/A *
2372N/A * @return {@code true} if the provided value is 7-bit clean, or {@code false}
2372N/A * if it is not.
2372N/A */
4134N/A private final boolean is7BitClean(ByteSequence value)
2372N/A {
4134N/A byte b;
4134N/A for (int i = 0; i < value.length(); i++)
2372N/A {
4134N/A b = value.byteAt(i);
2372N/A if ((b & MASK) != b)
2372N/A {
2372N/A return false;
2372N/A }
2372N/A }
2372N/A
2372N/A return true;
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * {@inheritDoc}
2372N/A */
2372N/A @Override()
2372N/A public boolean isConfigurationAcceptable(PluginCfg configuration,
2372N/A List<Message> unacceptableReasons)
2372N/A {
2372N/A SevenBitCleanPluginCfg cfg = (SevenBitCleanPluginCfg) configuration;
2372N/A return isConfigurationChangeAcceptable(cfg, unacceptableReasons);
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * {@inheritDoc}
2372N/A */
2372N/A public boolean isConfigurationChangeAcceptable(
2372N/A SevenBitCleanPluginCfg configuration,
2372N/A List<Message> unacceptableReasons)
2372N/A {
2372N/A boolean configAcceptable = true;
2372N/A
2372N/A // Ensure that the set of plugin types is acceptable.
2372N/A for (PluginCfgDefn.PluginType pluginType : configuration.getPluginType())
2372N/A {
2372N/A switch (pluginType)
2372N/A {
2372N/A case LDIFIMPORT:
2372N/A case PREPARSEADD:
2372N/A case PREPARSEMODIFY:
2372N/A case PREPARSEMODIFYDN:
2372N/A // These are acceptable.
2372N/A break;
2372N/A
2372N/A
2372N/A default:
2372N/A Message message = ERR_PLUGIN_7BIT_INVALID_PLUGIN_TYPE.get(
2372N/A pluginType.toString());
2372N/A unacceptableReasons.add(message);
2372N/A configAcceptable = false;
2372N/A }
2372N/A }
2372N/A
2372N/A return configAcceptable;
2372N/A }
2372N/A
2372N/A
2372N/A
2372N/A /**
2372N/A * {@inheritDoc}
2372N/A */
2372N/A public ConfigChangeResult applyConfigurationChange(
2372N/A SevenBitCleanPluginCfg configuration)
2372N/A {
2372N/A currentConfig = configuration;
2372N/A return new ConfigChangeResult(ResultCode.SUCCESS, false);
2372N/A }
2372N/A}
2372N/A