blob: dfedd8dd93e63721f1b68f193f60a190d176af82 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.server.operations.modify;
import static org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContext;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Arrays;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.NoPermissionException;
import javax.naming.directory.Attribute;
import javax.naming.directory.AttributeInUseException;
import javax.naming.directory.AttributeModificationException;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InvalidAttributeValueException;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.NoSuchAttributeException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.apache.directory.api.ldap.model.entry.DefaultEntry;
import org.apache.directory.api.ldap.model.entry.DefaultModification;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.entry.ModificationOperation;
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.ldif.LdifUtils;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.api.util.Strings;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
import org.apache.directory.server.annotations.CreateLdapServer;
import org.apache.directory.server.annotations.CreateTransport;
import org.apache.directory.server.core.annotations.ApplyLdifs;
import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
import org.apache.directory.server.core.integ.FrameworkRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Test case with different modify operations on a person entry. Each includes a
* single add op only. Created to demonstrate DIREVE-241 ("Adding an already
* existing attribute value with a modify operation does not cause an error.").
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
@RunWith(FrameworkRunner.class)
@ApplyLdifs(
{
// Entry # 1
"dn: cn=Tori Amos,ou=system",
"objectClass: inetOrgPerson",
"objectClass: organizationalPerson",
"objectClass: person",
"objectClass: top",
"description: an American singer-songwriter",
"cn: Tori Amos",
"sn: Amos",
// Entry # 2
"dn: cn=Debbie Harry,ou=system",
"objectClass: inetOrgPerson",
"objectClass: organizationalPerson",
"objectClass: person",
"objectClass: top",
"cn: Debbie Harry",
"sn: Harry" })
//@CreateDS( allowAnonAccess=true, name="BindIT-class")
@CreateLdapServer(
transports =
{
@CreateTransport(protocol = "LDAP") })
public class ModifyAddIT extends AbstractLdapTestUnit
{
private static final String BASE = "ou=system";
private static final String RDN_TORI_AMOS = "cn=Tori Amos";
private static final String PERSON_DESCRIPTION = "an American singer-songwriter";
private static final String RDN_DEBBIE_HARRY = "cn=Debbie Harry";
/**
* Creation of required attributes of a person entry.
*/
protected Attributes getPersonAttributes( String sn, String cn ) throws LdapException
{
Attributes attributes = LdifUtils.createJndiAttributes(
"objectClass: top",
"objectClass: person",
"objectClass: organizationalperson",
"objectClass: inetorgperson",
"cn", cn,
"sn", sn );
return attributes;
}
/**
* Add a new attribute to a person entry.
*/
@Test
public void testAddNewAttributeValue() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Add telephoneNumber attribute
String newValue = "1234567890";
Attributes attrs = new BasicAttributes( "telephoneNumber", newValue, true );
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
// Verify, that
// - case of attribute description is correct
// - attribute value is added
attrs = ctx.getAttributes( RDN_TORI_AMOS );
Attribute attr = attrs.get( "telephoneNumber" );
assertNotNull( attr );
assertEquals( "telephoneNumber", attr.getID() );
assertTrue( attr.contains( newValue ) );
assertEquals( 1, attr.size() );
}
/**
* Add a new attribute with two values.
*/
@Test
public void testAddNewAttributeValues() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Add telephoneNumber attribute
String[] newValues =
{ "1234567890", "999999999" };
Attribute attr = new BasicAttribute( "telephoneNumber" );
attr.add( newValues[0] );
attr.add( newValues[1] );
Attributes attrs = new BasicAttributes( true );
attrs.put( attr );
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
// Verify, that
// - case of attribute description is correct
// - attribute values are present
attrs = ctx.getAttributes( RDN_TORI_AMOS );
attr = attrs.get( "telephoneNumber" );
assertNotNull( attr );
assertEquals( "telephoneNumber", attr.getID() );
assertTrue( attr.contains( newValues[0] ) );
assertTrue( attr.contains( newValues[1] ) );
assertEquals( newValues.length, attr.size() );
}
/**
* Add an additional value.
*/
@Test
public void testAddAdditionalAttributeValue() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// A new description attribute value
String newValue = "A new description for this person";
assertFalse( newValue.equals( PERSON_DESCRIPTION ) );
Attributes attrs = new BasicAttributes( "description", newValue, true );
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
// Verify, that attribute value is added
attrs = ctx.getAttributes( RDN_TORI_AMOS );
Attribute attr = attrs.get( "description" );
assertNotNull( attr );
assertTrue( attr.contains( newValue ) );
assertTrue( attr.contains( PERSON_DESCRIPTION ) );
assertEquals( 2, attr.size() );
}
/**
* Try to add an already existing attribute value.
*
* Expected behaviour: Modify operation fails with an
* AttributeInUseException. Original LDAP Error code: 20 (Indicates that the
* attribute value specified in a modify or add operation already exists as
* a value for that attribute).
*/
@Test
public void testAddExistingAttributeValue() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Change description attribute
Attributes attrs = new BasicAttributes( "description", PERSON_DESCRIPTION, true );
try
{
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
fail( "Adding an already existing atribute value should fail." );
}
catch ( AttributeInUseException e )
{
// expected behaviour
}
// Verify, that attribute is still there, and is the only one
attrs = ctx.getAttributes( RDN_TORI_AMOS );
Attribute attr = attrs.get( "description" );
assertNotNull( attr );
assertTrue( attr.contains( PERSON_DESCRIPTION ) );
assertEquals( 1, attr.size() );
}
/**
* Try to add an already existing attribute value.
*
* Expected behaviour: Modify operation fails with an
* AttributeInUseException. Original LDAP Error code: 20 (Indicates that the
* attribute value specified in a modify or add operation already exists as
* a value for that attribute).
*
* Check for bug DIR_SERVER664
*/
@Test
public void testAddExistingNthAttributesDirServer664() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Change description attribute
Attributes attrs = new BasicAttributes( true );
attrs.put( new BasicAttribute( "telephoneNumber", "1" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "2" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "3" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "4" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "5" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "6" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "7" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "8" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "9" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "10" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "11" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "12" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "13" ) );
attrs.put( new BasicAttribute( "telephoneNumber", "14" ) );
Attribute attr = new BasicAttribute( "description", PERSON_DESCRIPTION );
attrs.put( attr );
try
{
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
fail( "Adding an already existing atribute value should fail." );
}
catch ( AttributeInUseException e )
{
// expected behaviour
}
// Verify, that attribute is still there, and is the only one
attrs = ctx.getAttributes( RDN_TORI_AMOS );
attr = attrs.get( "description" );
assertNotNull( attr );
assertTrue( attr.contains( PERSON_DESCRIPTION ) );
assertEquals( 1, attr.size() );
}
/**
* Check for DIR_SERVER_643
*/
@Test
public void testTwoDescriptionDirServer643() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Change description attribute
Attributes attrs = new BasicAttributes( true );
Attribute attr = new BasicAttribute( "description",
"a British singer-songwriter with an expressive four-octave voice" );
attr.add( "one of the most influential female artists of the twentieth century" );
attrs.put( attr );
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
// Verify, that attribute is still there, and is the only one
attrs = ctx.getAttributes( RDN_TORI_AMOS );
attr = attrs.get( "description" );
assertNotNull( attr );
assertEquals( 3, attr.size() );
assertTrue( attr.contains( "a British singer-songwriter with an expressive four-octave voice" ) );
assertTrue( attr.contains( "one of the most influential female artists of the twentieth century" ) );
assertTrue( attr.contains( PERSON_DESCRIPTION ) );
}
/**
* Try to add a duplicate attribute value to an entry, where this attribute
* is already present (objectclass in this case). Expected behaviour is that
* the modify operation causes an error (error code 20, "Attribute or value
* exists").
*/
@Test
public void testAddDuplicateValueToExistingAttribute() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// modify object classes, add a new value twice
Attribute ocls = new BasicAttribute( "objectClass", "organizationalPerson" );
ModificationItem[] modItems = new ModificationItem[2];
modItems[0] = new ModificationItem( DirContext.ADD_ATTRIBUTE, ocls );
modItems[1] = new ModificationItem( DirContext.ADD_ATTRIBUTE, ocls );
try
{
ctx.modifyAttributes( RDN_TORI_AMOS, modItems );
fail( "Adding a duplicate attribute value should cause an error." );
}
catch ( AttributeInUseException ex )
{
}
// Check, whether attribute objectClass is unchanged
Attributes attrs = ctx.getAttributes( RDN_TORI_AMOS );
ocls = attrs.get( "objectClass" );
assertEquals( ocls.size(), 4 );
assertTrue( ocls.contains( "top" ) );
assertTrue( ocls.contains( "person" ) );
}
/**
* Try to add a duplicate attribute value to an entry, where this attribute
* is not present. Expected behaviour is that the modify operation causes an
* error (error code 20, "Attribute or value exists").
*/
@Test
public void testAddDuplicateValueToNewAttribute() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// add the same description value twice
Attribute desc = new BasicAttribute( "description", "another description value besides songwriter" );
ModificationItem[] modItems = new ModificationItem[2];
modItems[0] = new ModificationItem( DirContext.ADD_ATTRIBUTE, desc );
modItems[1] = new ModificationItem( DirContext.ADD_ATTRIBUTE, desc );
try
{
ctx.modifyAttributes( RDN_TORI_AMOS, modItems );
fail( "Adding a duplicate attribute value should cause an error." );
}
catch ( AttributeInUseException ex )
{
}
// Check, whether attribute description is still not present
Attributes attrs = ctx.getAttributes( RDN_TORI_AMOS );
assertEquals( 1, attrs.get( "description" ).size() );
}
/**
* Modify the entry with a bad attribute : this should fail
*/
@Test
public void testSearchBadAttribute() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Add a not existing attribute
String newValue = "unbelievable";
Attributes attrs = new BasicAttributes( "voice", newValue, true );
try
{
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
}
catch ( NoSuchAttributeException nsae )
{
// We have a failure : the attribute is unknown in the schema
assertTrue( true );
return;
}
fail( "Cannot reach this point" );
}
/**
* Create a person entry and perform a modify op, in which
* we modify an attribute two times.
*/
@Test
public void testAttributeValueMultiMofificationDIRSERVER_636() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Create a person entry
Attributes attrs = getPersonAttributes( "Bush", "Kate Bush" );
String rdn = "cn=Kate Bush";
ctx.createSubcontext( rdn, attrs );
// Add a description with two values
String[] descriptions =
{
"Kate Bush is a British singer-songwriter.",
"She has become one of the most influential female artists of the twentieth century." };
Attribute desc1 = new BasicAttribute( "description" );
desc1.add( descriptions[0] );
desc1.add( descriptions[1] );
ModificationItem addModOp = new ModificationItem(
DirContext.ADD_ATTRIBUTE, desc1 );
Attribute desc2 = new BasicAttribute( "description" );
desc2.add( descriptions[1] );
ModificationItem delModOp = new ModificationItem(
DirContext.REMOVE_ATTRIBUTE, desc2 );
ctx.modifyAttributes( rdn, new ModificationItem[]
{ addModOp,
delModOp } );
SearchControls sctls = new SearchControls();
sctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
String filter = "(cn=*Bush)";
String base = "";
// Check entry
NamingEnumeration<SearchResult> enm = ctx.search( base, filter, sctls );
assertTrue( enm.hasMore() );
while ( enm.hasMore() )
{
SearchResult sr = enm.next();
attrs = sr.getAttributes();
Attribute desc = sr.getAttributes().get( "description" );
assertEquals( 1, desc.size() );
assertTrue( desc.contains( descriptions[0] ) );
}
// Remove the person entry
ctx.destroySubcontext( rdn );
}
/**
* Try to add subschemaSubentry attribute to an entry
*/
@Test
public void testModifyOperationalAttributeAdd() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
ModificationItem modifyOp = new ModificationItem( DirContext.ADD_ATTRIBUTE, new BasicAttribute(
"subschemaSubentry", "cn=anotherSchema" ) );
try
{
ctx.modifyAttributes( RDN_DEBBIE_HARRY, new ModificationItem[]
{ modifyOp } );
fail( "modification of entry should fail" );
}
catch ( InvalidAttributeValueException e )
{
// Expected result
}
catch ( NoPermissionException e )
{
// Expected result
}
}
/**
* Create a person entry and perform a modify op on an
* attribute which is part of the Dn. This is not allowed.
*
* A JIRA has been created for this bug : DIRSERVER_687
*/
@Test
public void testDNAttributeMemberModificationDIRSERVER_687() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Create a person entry
Attributes attrs = getPersonAttributes( "Bush", "Kate Bush" );
String rdn = "cn=Kate Bush";
ctx.createSubcontext( rdn, attrs );
// Try to modify the cn attribute
Attribute desc1 = new BasicAttribute( "cn", "Georges Bush" );
ModificationItem addModOp = new ModificationItem(
DirContext.REPLACE_ATTRIBUTE, desc1 );
try
{
ctx.modifyAttributes( rdn, new ModificationItem[]
{ addModOp } );
fail();
}
catch ( AttributeModificationException ame )
{
assertTrue( true );
// Remove the person entry
ctx.destroySubcontext( rdn );
}
catch ( NamingException ne )
{
assertTrue( true );
// Remove the person entry
ctx.destroySubcontext( rdn );
}
}
/**
* Try to modify an entry adding invalid number of values for a single-valued atribute
*
* @see <a href="http://issues.apache.org/jira/browse/DIRSERVER-614">DIRSERVER-614</a>
*/
@Test
public void testModifyAddWithInvalidNumberOfAttributeValues() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
Attributes attrs = new BasicAttributes( true );
Attribute ocls = new BasicAttribute( "objectClass" );
ocls.add( "top" );
ocls.add( "inetOrgPerson" );
attrs.put( ocls );
attrs.put( "cn", "Fiona Apple" );
attrs.put( "sn", "Apple" );
ctx.createSubcontext( "cn=Fiona Apple", attrs );
// add two displayNames to an inetOrgPerson
attrs = new BasicAttributes( true );
Attribute displayName = new BasicAttribute( "displayName" );
displayName.add( "Fiona" );
displayName.add( "Fiona A." );
attrs.put( displayName );
try
{
ctx.modifyAttributes( "cn=Fiona Apple", DirContext.ADD_ATTRIBUTE, attrs );
fail( "modification of entry should fail" );
}
catch ( InvalidAttributeValueException e )
{
}
}
/**
* Add a new binary attribute to a person entry.
*/
@Test
public void testAddNewBinaryAttributeValue() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Add a binary attribute
byte[] newValue = new byte[]
{ 0x00, 0x01, 0x02, 0x03 };
Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue, true );
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
// Verify, that attribute value is added
attrs = ctx.getAttributes( RDN_TORI_AMOS );
Attribute attr = attrs.get( "userCertificate" );
assertNotNull( attr );
assertTrue( attr.contains( newValue ) );
byte[] certificate = ( byte[] ) attr.get();
assertTrue( Arrays.equals( newValue, certificate ) );
assertEquals( 1, attr.size() );
}
/**
* Add a new attribute to a person entry.
*/
@Test
public void testAddNewBinaryAttributeValueAbove0x80() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Add a binary attribute
byte[] newValue = new byte[]
{ ( byte ) 0x80, ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83 };
Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue, true );
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
// Verify, that attribute value is added
attrs = ctx.getAttributes( RDN_TORI_AMOS );
Attribute attr = attrs.get( "userCertificate" );
assertNotNull( attr );
assertTrue( attr.contains( newValue ) );
byte[] certificate = ( byte[] ) attr.get();
assertTrue( Arrays.equals( newValue, certificate ) );
assertEquals( 1, attr.size() );
}
/**
* Add a new binary attribute to a person entry.
*/
@Test
public void testRetrieveEntryWithBinaryAttributeValue() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Add a ;binary attribute
byte[] newValue = new byte[]
{ 0x00, 0x01, 0x02, 0x03 };
Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue );
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
// Search entry an request ;binary attribute
SearchControls sctls = new SearchControls();
sctls.setSearchScope( SearchControls.OBJECT_SCOPE );
sctls.setReturningAttributes( new String[]
{ "userCertificate;binary" } );
String filter = "(objectClass=*)";
String base = RDN_TORI_AMOS;
// Test that ;binary attribute is present
NamingEnumeration<SearchResult> enm = ctx.search( base, filter, sctls );
assertTrue( enm.hasMore() );
while ( enm.hasMore() )
{
SearchResult sr = enm.next();
attrs = sr.getAttributes();
Attribute attr = attrs.get( "userCertificate" );
assertNotNull( attr );
assertTrue( attr.contains( newValue ) );
byte[] certificate = ( byte[] ) attr.get();
assertTrue( Arrays.equals( newValue, certificate ) );
assertEquals( 1, attr.size() );
}
}
/**
* Add a new ;binary attribute with bytes greater than 0x80
* to a person entry.
* Test for DIRSERVER-1146
*
* @throws NamingException
*/
public void testAddNewBinaryAttributeValue0x80() throws Exception
{
DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
// Add a ;binary attribute with high-bytes
byte[] newValue = new byte[]
{ ( byte ) 0x80, ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83 };
Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue );
ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
// Verify, that attribute value is added
attrs = ctx.getAttributes( RDN_TORI_AMOS );
Attribute attr = attrs.get( "userCertificate" );
assertNotNull( attr );
assertTrue( attr.contains( newValue ) );
byte[] certificate = ( byte[] ) attr.get();
assertTrue( Arrays.equals( newValue, certificate ) );
assertEquals( 1, attr.size() );
}
@Test
public void testModifyAddWithNullValues() throws LdapException, IOException
{
LdapConnection connection = new LdapNetworkConnection( "localhost", getLdapServer().getPort() );
connection.setTimeOut( 0L );
// Use the client API
connection.bind( "uid=admin,ou=system", "secret" );
// Add a new entry with some null values
Entry entry = new DefaultEntry( "uid=12345,ou=system",
"ObjectClass: top",
"ObjectClass: person",
"ObjectClass: person",
"ObjectClass: OrganizationalPerson",
"ObjectClass: inetOrgPerson",
"uid: 12345",
"cn: test",
"sn: Test",
"userPassword: 12345" );
connection.add( entry );
// Now modify the entry : we should add two null values
connection.modify( new Dn( "uid=12345,ou=system" ),
new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "userPassword", Strings.EMPTY_BYTES ),
new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "mail", ( String ) null )
);
// Get back the entry
Entry found = connection.lookup( "uid=12345,ou=system" );
assertNotNull( found );
assertNotNull( found.get( "mail" ) );
assertNotNull( found.get( "userPassword" ) );
assertTrue( found.contains( "mail", Strings.EMPTY_BYTES ) );
assertTrue( found.contains( "userPassword", "12345", "" ) );
connection.close();
}
@Test
public void testModifyReplaceWithNullValues() throws LdapException, IOException
{
LdapConnection connection = new LdapNetworkConnection( "localhost", getLdapServer().getPort() );
connection.setTimeOut( 0L );
// Use the client API
connection.bind( "uid=admin,ou=system", "secret" );
// Add a new entry with some null values
Entry entry = new DefaultEntry( "uid=12345,ou=system",
"ObjectClass: top",
"ObjectClass: person",
"ObjectClass: person",
"ObjectClass: OrganizationalPerson",
"ObjectClass: inetOrgPerson",
"uid: 12345",
"cn: test",
"sn: Test",
"userPassword: 12345" );
connection.add( entry );
// Now modify the entry : we should replace the password with a null value
// and add a mail Attribute with a null value
connection.modify( new Dn( "uid=12345,ou=system" ),
new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, "userPassword", Strings.EMPTY_BYTES ),
new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "mail", ( String ) null )
);
// Get back the entry
Entry found = connection.lookup( "uid=12345,ou=system" );
assertNotNull( found );
assertNotNull( found.get( "mail" ) );
assertNotNull( found.get( "userPassword" ) );
assertEquals( 1, found.get( "mail" ).size() );
assertEquals( 1, found.get( "userPassword" ).size() );
assertTrue( found.contains( "mail", Strings.EMPTY_BYTES ) );
assertTrue( found.contains( "userPassword", "" ) );
// Now, do a replace with no value. We should not anymore have a mail
connection.modify( new Dn( "uid=12345,ou=system" ),
new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, "mail" )
);
// Get back the entry
found = connection.lookup( "uid=12345,ou=system" );
assertNotNull( found );
assertNull( found.get( "mail" ) );
assertNotNull( found.get( "userPassword" ) );
assertEquals( 1, found.get( "userPassword" ).size() );
assertTrue( found.contains( "userPassword", "" ) );
connection.close();
}
}