/* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2011 profiq s.r.o. * Portions Copyright 2013-2016 ForgeRock AS. */ package org.opends.server.plugins; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.forgerock.opendj.config.server.ConfigException; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.ModificationType; import org.forgerock.opendj.ldap.ResultCode; import org.opends.server.TestCaseUtils; import org.forgerock.opendj.server.config.meta.AttributeCleanupPluginCfgDefn; import org.opends.server.api.plugin.PluginResult; import org.opends.server.core.AddOperationBasis; import org.opends.server.core.ModifyOperationBasis; import org.opends.server.extensions.InitializationUtils; import org.opends.server.types.Entry; import org.opends.server.types.InitializationException; import org.opends.server.types.RawAttribute; import org.opends.server.types.RawModification; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.forgerock.opendj.ldap.ModificationType.*; import static org.opends.server.protocols.internal.InternalClientConnection.*; import static org.opends.server.util.CollectionUtils.*; import static org.testng.Assert.*; /** Tests for the attribute cleanup plugin. */ @SuppressWarnings("javadoc") public class AttributeCleanupPluginTestCase extends PluginTestCase { @BeforeClass public void startServer() throws Exception { TestCaseUtils.startServer(); } @DataProvider(name = "validConfigs") public Object[][] getValidConfigs() throws Exception { List entries = TestCaseUtils.makeEntries( "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin", "", "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin", "ds-cfg-remove-inbound-attributes: modifyTimeStamp", "ds-cfg-remove-inbound-attributes: createTimeStamp", "", "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin", "ds-cfg-rename-inbound-attributes: cn:uid"); return toArrayArray(entries); } @Test(dataProvider = "validConfigs") public void testInitializeWithValidConfigs(Entry e) throws Exception { AttributeCleanupPlugin plugin = initializePlugin(e); plugin.finalizePlugin(); } @DataProvider(name = "invalidConfigs") public Object[][] getInvalidConfigs() throws Exception { List entries = TestCaseUtils.makeEntries( /* local attribute is not defined */ "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin", "ds-cfg-rename-inbound-attributes: cn:badAttr", "", /* duplicate attributes */ "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin", "ds-cfg-rename-inbound-attributes: cn:uid", "ds-cfg-rename-inbound-attributes: cn:description", "", /* self mapping */ "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin", "ds-cfg-rename-inbound-attributes: cn:cn"); return toArrayArray(entries); } private Object[][] toArrayArray(List entries) { Object[][] array = new Object[entries.size()][1]; for (int i=0; i < array.length; i++) { array[i] = new Object[] { entries.get(i) }; } return array; } @Test(dataProvider = "invalidConfigs", expectedExceptions = { ConfigException.class } ) public void testInitializeWithInvalidConfigs(Entry e) throws ConfigException, InitializationException { AttributeCleanupPlugin plugin = initializePlugin(e); plugin.finalizePlugin(); } /** * Verifies the attribute renaming in the incoming ADD operation. * * @throws Exception in case of bugs. */ @Test public void testRenameAttributesForAddOperation() throws Exception { // Configure the plugin to rename incoming 'cn' attributes to 'description'. Entry confEntry = TestCaseUtils.makeEntry( "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-rename-inbound-attributes: cn:description", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin"); AttributeCleanupPlugin plugin = initializePlugin(confEntry); /* Construct the ADD operation as follows: * * dn: uid=test,dc=example,dc=com * objectClass: top * objectClass: person * objectClass: organizationalPerson * objectClass: inetOrgPerson * uid: test * cn: Name Surname * sn: Surname */ AddOperationBasis addOperation = add("dn: uid=test,dc=example,dc=com", RawAttribute.create("objectClass", toByteStrings("top", "person", "organizationalperson", "inetorgperson")), RawAttribute.create("uid", "test"), RawAttribute.create("cn", "Name Surname"), RawAttribute.create("sn", "Surname")); /* Process the operation. The processing should continue. */ PluginResult.PreParse res = plugin.doPreParse(addOperation); assertTrue(res.continueProcessing()); /* Verify that the 'cn' attribute has been renamed to 'description' * by getting the 'decription' attribute and matching the value with * the original 'cn' value. */ List rawAttrs = addOperation.getRawAttributes(); assertNotNull(rawAttrs); for(RawAttribute rawAttr : rawAttrs) { if(rawAttr.getAttributeType().equalsIgnoreCase("description")) { List attrVals = rawAttr.getValues(); assertEquals("Name Surname", attrVals.get(0).toString()); plugin.finalizePlugin(); return; } } fail(); } private ArrayList toByteStrings(String... strings) { ArrayList results = new ArrayList<>(strings.length); for (String s : strings) { results.add(ByteString.valueOfUtf8(s)); } return results; } private AddOperationBasis add(String entryDN, RawAttribute... rawAttributes) { return new AddOperationBasis(getRootConnection(), 1, 1, null, ByteString.valueOfUtf8(entryDN), Arrays.asList(rawAttributes)); } /** * Verifies the attribute removal in the incoming ADD request. * @throws Exception in case of bugs. */ @Test public void testRemoveAttributesForAddOperation() throws Exception { /* Configure the plugin to remove 'modifyTimeStamp' and * 'createTimeStamp' attributes from the incoming ADD requests. */ Entry confEntry = TestCaseUtils.makeEntry( "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-remove-inbound-attributes: modifyTimeStamp", "ds-cfg-remove-inbound-attributes: createTimeStamp", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin"); AttributeCleanupPlugin plugin = initializePlugin(confEntry); /* Create the ADD operation as follows: * * dn: uid=test,dc=example,dc=com * objectClass: top * objectClass: person * objectClass: organizationalPerson * objectClass: inetOrgPerson * uid: test * cn: Name Surname * sn: Surname * modifyTimeStamp: 2011091212400000Z * createTimeStamp: 2011091212400000Z */ AddOperationBasis addOperation = add("dn: uid=test,dc=example,dc=com", RawAttribute.create("objectClass", toByteStrings("top", "person", "organizationalperson", "inetorgperson")), RawAttribute.create("uid", "test"), RawAttribute.create("cn", "Name Surname"), RawAttribute.create("sn", "Surname"), RawAttribute.create("modifyTimeStamp", "2011091212400000Z"), RawAttribute.create("createTimeStamp", "2011091212400000Z")); /* Process the operation and expect the server to continue * processing the operation. */ PluginResult.PreParse res = plugin.doPreParse(addOperation); assertTrue(res.continueProcessing()); /* Verify that the '*TimeStamp' attributes have been removed. */ List rawAttrs = addOperation.getRawAttributes(); assertNotNull(rawAttrs); for(RawAttribute rawAttr : rawAttrs) { assertFalse(rawAttr.getAttributeType().equalsIgnoreCase("modifyTimeStamp") || rawAttr.getAttributeType().equalsIgnoreCase("createTimeStamp"), "Attribute '" + rawAttr.getAttributeType() + "' exists and it shouldn't"); } plugin.finalizePlugin(); } /** * In some cases the plugin might remove all attributes from the * incoming MODIFY request which would make the request invalid by the * LDAP standards. However, this is a special case and the request * should be silently dropped while the client should be notified of * SUCCESS. * @throws Exception in case of a bug. */ @Test public void testRemoveAttributesForModifyOperationInvalid() throws Exception { /* Configure the plugin to remove 'modifyTimeStamp' and * 'createTimeStamp' attributes from the incoming MODIFY request. */ Entry confEntry = TestCaseUtils.makeEntry( "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-remove-inbound-attributes: modifyTimeStamp", "ds-cfg-remove-inbound-attributes: createTimeStamp", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin"); AttributeCleanupPlugin plugin = initializePlugin(confEntry); /* Create the MODIFY request as follows: * * dn: uid=test,dc=example,dc=com * changetype: modify * replace: modifyTimeStamp * modifyTimeStamp: 2011091212400000Z * - * replace: createTimeStamp * createTimeStamp: 2011091212400000Z * - */ ModifyOperationBasis modifyOperation = modify("dn: uid=test,dc=example,dc=com", newRawModification(REPLACE, "modifyTimeStamp", "2011091212400000Z"), newRawModification(REPLACE, "createTimeStamp", "2011091212400000Z")); /* Process the request. The result should be SUCCESS and the server * should stop the processing. */ PluginResult.PreParse res = plugin.doPreParse(modifyOperation); assertFalse(res.continueProcessing()); assertSame(res.getResultCode(), ResultCode.SUCCESS); plugin.finalizePlugin(); } private AttributeCleanupPlugin initializePlugin(Entry confEntry) throws ConfigException, InitializationException { return InitializationUtils.initializePlugin( new AttributeCleanupPlugin(), confEntry, AttributeCleanupPluginCfgDefn.getInstance()); } private ModifyOperationBasis modify(String entryDN, RawModification... rawMods) { return new ModifyOperationBasis( getRootConnection(), 1, 1, null, ByteString.valueOfUtf8(entryDN), newArrayList(rawMods)); } /** * Verify the attribute renaming for a MODIFY operation. * @throws Exception in case of a bug. */ @Test public void testRemoveAttributesForModifyOperationValid() throws Exception { /* Configure the plugin to remove 'modifyTimeStamp' and * 'createTimeStamp' attributes from the incoming requests. */ Entry confEntry = TestCaseUtils.makeEntry( "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-remove-inbound-attributes: modifyTimeStamp", "ds-cfg-remove-inbound-attributes: createTimeStamp", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin"); AttributeCleanupPlugin plugin = initializePlugin(confEntry); /* Create the MODIFY operation as follows: * * dn: uid=test,dc=example,dc=com * changetype: modify * replace: cn * cn: Test User * - * replace: sn * sn: User * - * replace: modifyTimeStamp * modifyTimeStamp: 2011091212400000Z * - * replace: createTimeStamp * createTimeStamp: 2011091212400000Z * - */ ModifyOperationBasis modifyOperation = modify("dn: uid=test,dc=example,dc=com", newRawModification(REPLACE, "cn", "Test User"), newRawModification(REPLACE, "sn", "User"), newRawModification(REPLACE, "modifyTimeStamp", "2011091212400000Z"), newRawModification(REPLACE, "createTimeStamp", "2011091212400000Z")); /* Process the MODIFY operation making sure the remaining number of * modifications is 2 and that the '*TimeStamp' modifications are * removed. */ plugin.doPreParse(modifyOperation); assertEquals(modifyOperation.getRawModifications().size(), 2); List rawMods = modifyOperation.getRawModifications(); assertNotNull(rawMods); for(RawModification rawMod : rawMods ) { RawAttribute modAttr = rawMod.getAttribute(); if(modAttr.getAttributeType().equalsIgnoreCase("modifyTimeStamp") || modAttr.getAttributeType().equalsIgnoreCase("createTimeStamp")) { fail("Attribute '" + modAttr.getAttributeType() + "' exists and it shouldn't"); } } plugin.finalizePlugin(); } private RawModification newRawModification(ModificationType modType, String attrName, String attrValue) { return RawModification.create(modType, attrName, attrValue); } /** * Verify the attribute renaming for the MODIFY operation. */ @Test public void testRenameAttributesForModifyOperation() throws Exception { /* Configure the plugin to rename the 'modifyTimeStamp' attribute to * 'description'. */ Entry confEntry = TestCaseUtils.makeEntry( "dn: cn=Attribute Cleanup,cn=Plugins,cn=config", "objectClass: top", "objectClass: ds-cfg-plugin", "objectClass: ds-cfg-attribute-cleanup-plugin", "cn: Attribute Cleanup", "ds-cfg-enabled: true", "ds-cfg-plugin-type: preparseadd", "ds-cfg-plugin-type: preparsemodify", "ds-cfg-rename-inbound-attributes: modifyTimeStamp:description", "ds-cfg-java-class: org.opends.server.plugins.AttributeCleanupPlugin"); AttributeCleanupPlugin plugin = initializePlugin(confEntry); /* Create the MODIFY operation as follows: * * dn: uid=test,dc=exampple,dc=com * changetype: modify * replace: cn * cn: Test User * - * replace: sn * sn: User * - * replace: modifyTimeStamp * modifyTimeStamp: 2011091212400000Z */ ModifyOperationBasis modifyOperation = modify("dn: uid=test,dc=example,dc=com", newRawModification(REPLACE, "cn", "Test User"), newRawModification(REPLACE, "sn", "User"), newRawModification(REPLACE, "modifyTimeStamp", "2011091212400000Z")); /* Process the MODIFY operation. */ PluginResult.PreParse res = plugin.doPreParse(modifyOperation); assertTrue(res.continueProcessing()); /* Verify that the attribute has been properly renamed by comparing * the value of the attribute 'description' with the original value * of the 'modifyTimeStamp' attribute. */ List rawMods = modifyOperation.getRawModifications(); assertNotNull(rawMods); for(RawModification rawMod : rawMods ) { RawAttribute modAttr = rawMod.getAttribute(); if (modAttr.getAttributeType().equalsIgnoreCase("description")) { List descrValues = modAttr.getValues(); assertEquals("2011091212400000Z", descrValues.get(0).toString()); plugin.finalizePlugin(); return; } assertFalse(modAttr.getAttributeType().equalsIgnoreCase("modifyTimeStamp"), "modifyTimeStamp shouldn't exist but it does."); } fail(); } }