| /* |
| * 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; |
| |
| |
| import java.util.Hashtable; |
| |
| import javax.naming.NamingEnumeration; |
| import javax.naming.NamingException; |
| import javax.naming.directory.Attribute; |
| import javax.naming.directory.AttributeInUseException; |
| import javax.naming.directory.Attributes; |
| import javax.naming.directory.DirContext; |
| import javax.naming.directory.InvalidAttributeIdentifierException; |
| import javax.naming.directory.InvalidAttributeValueException; |
| import javax.naming.directory.SearchControls; |
| import javax.naming.directory.SearchResult; |
| import javax.naming.ldap.InitialLdapContext; |
| import javax.naming.ldap.LdapContext; |
| |
| import org.apache.directory.server.unit.AbstractServerTest; |
| import org.apache.directory.shared.ldap.message.LockableAttributeImpl; |
| import org.apache.directory.shared.ldap.message.LockableAttributesImpl; |
| import org.apache.directory.shared.ldap.message.ModificationItemImpl; |
| |
| |
| /** |
| * Testcase 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> |
| * @version $Rev$ |
| */ |
| public class ModifyAddTest extends AbstractServerTest |
| { |
| private LdapContext ctx = null; |
| public static final String RDN = "cn=Tori Amos"; |
| public static final String PERSON_DESCRIPTION = "an American singer-songwriter"; |
| |
| |
| /** |
| * Creation of required attributes of a person entry. |
| */ |
| protected Attributes getPersonAttributes( String sn, String cn ) |
| { |
| Attributes attributes = new LockableAttributesImpl(); |
| Attribute attribute = new LockableAttributeImpl( "objectClass" ); |
| attribute.add( "top" ); |
| attribute.add( "person" ); |
| attributes.put( attribute ); |
| attributes.put( "cn", cn ); |
| attributes.put( "sn", sn ); |
| |
| return attributes; |
| } |
| |
| |
| /** |
| * Create context and a person entry. |
| */ |
| protected void setUp() throws Exception |
| { |
| super.setUp(); |
| |
| Hashtable env = new Hashtable(); |
| env.put( "java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory" ); |
| env.put( "java.naming.provider.url", "ldap://localhost:" + port + "/ou=system" ); |
| env.put( "java.naming.security.principal", "uid=admin,ou=system" ); |
| env.put( "java.naming.security.credentials", "secret" ); |
| env.put( "java.naming.security.authentication", "simple" ); |
| |
| ctx = new InitialLdapContext( env, null ); |
| assertNotNull( ctx ); |
| |
| // Create a person with description |
| Attributes attributes = this.getPersonAttributes( "Amos", "Tori Amos" ); |
| attributes.put( "description", "an American singer-songwriter" ); |
| ctx.createSubcontext( RDN, attributes ); |
| |
| } |
| |
| |
| /** |
| * Remove person entry and close context. |
| */ |
| protected void tearDown() throws Exception |
| { |
| ctx.unbind( RDN ); |
| ctx.close(); |
| ctx = null; |
| super.tearDown(); |
| } |
| |
| |
| /** |
| * Add a new attribute to a person entry. |
| * |
| * @throws NamingException |
| */ |
| public void testAddNewAttributeValue() throws NamingException |
| { |
| // Add telephoneNumber attribute |
| String newValue = "1234567890"; |
| Attributes attrs = new LockableAttributesImpl( "telephoneNumber", newValue ); |
| ctx.modifyAttributes( RDN, DirContext.ADD_ATTRIBUTE, attrs ); |
| |
| // Verify, that attribute value is added |
| attrs = ctx.getAttributes( RDN ); |
| Attribute attr = attrs.get( "telephoneNumber" ); |
| assertNotNull( attr ); |
| assertTrue( attr.contains( newValue ) ); |
| assertEquals( 1, attr.size() ); |
| } |
| |
| |
| /** |
| * Add a new attribute with two values. |
| * |
| * @throws NamingException |
| */ |
| public void testAddNewAttributeValues() throws NamingException |
| { |
| // Add telephoneNumber attribute |
| String[] newValues = |
| { "1234567890", "999999999" }; |
| Attribute attr = new LockableAttributeImpl( "telephoneNumber" ); |
| attr.add( newValues[0] ); |
| attr.add( newValues[1] ); |
| Attributes attrs = new LockableAttributesImpl(); |
| attrs.put( attr ); |
| ctx.modifyAttributes( RDN, DirContext.ADD_ATTRIBUTE, attrs ); |
| |
| // Verify, that attribute values are present |
| attrs = ctx.getAttributes( RDN ); |
| attr = attrs.get( "telephoneNumber" ); |
| assertNotNull( attr ); |
| assertTrue( attr.contains( newValues[0] ) ); |
| assertTrue( attr.contains( newValues[1] ) ); |
| assertEquals( newValues.length, attr.size() ); |
| } |
| |
| |
| /** |
| * Add an additional value. |
| * |
| * @throws NamingException |
| */ |
| public void testAddAdditionalAttributeValue() throws NamingException |
| { |
| // A new description attribute value |
| String newValue = "A new description for this person"; |
| assertFalse( newValue.equals( PERSON_DESCRIPTION ) ); |
| Attributes attrs = new LockableAttributesImpl( "description", newValue ); |
| |
| ctx.modifyAttributes( RDN, DirContext.ADD_ATTRIBUTE, attrs ); |
| |
| // Verify, that attribute value is added |
| attrs = ctx.getAttributes( RDN ); |
| 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). |
| * |
| * @throws NamingException |
| */ |
| public void testAddExistingAttributeValue() throws NamingException |
| { |
| // Change description attribute |
| Attributes attrs = new LockableAttributesImpl( "description", PERSON_DESCRIPTION ); |
| |
| try |
| { |
| ctx.modifyAttributes( RDN, 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 ); |
| 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 |
| * |
| * @throws NamingException |
| */ |
| public void testAddExistingNthAttributesDirServer664() throws NamingException |
| { |
| // Change description attribute |
| Attributes attrs = new LockableAttributesImpl( true ); |
| attrs.put( new LockableAttributeImpl( "attr1", "attr 1" ) ); |
| attrs.put( new LockableAttributeImpl( "attr2", "attr 2" ) ); |
| attrs.put( new LockableAttributeImpl( "attr3", "attr 3" ) ); |
| attrs.put( new LockableAttributeImpl( "attr4", "attr 4" ) ); |
| attrs.put( new LockableAttributeImpl( "attr5", "attr 5" ) ); |
| attrs.put( new LockableAttributeImpl( "attr6", "attr 6" ) ); |
| attrs.put( new LockableAttributeImpl( "attr7", "attr 7" ) ); |
| attrs.put( new LockableAttributeImpl( "attr8", "attr 8" ) ); |
| attrs.put( new LockableAttributeImpl( "attr9", "attr 9" ) ); |
| attrs.put( new LockableAttributeImpl( "attr10", "attr 10" ) ); |
| attrs.put( new LockableAttributeImpl( "attr11", "attr 11" ) ); |
| attrs.put( new LockableAttributeImpl( "attr12", "attr 12" ) ); |
| attrs.put( new LockableAttributeImpl( "attr13", "attr 13" ) ); |
| attrs.put( new LockableAttributeImpl( "attr14", "attr 14" ) ); |
| |
| Attribute attr = new LockableAttributeImpl( "description", PERSON_DESCRIPTION ); |
| |
| attrs.put( attr ); |
| |
| try |
| { |
| ctx.modifyAttributes( RDN, 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 ); |
| attr = attrs.get( "description" ); |
| assertNotNull( attr ); |
| assertTrue( attr.contains( PERSON_DESCRIPTION ) ); |
| assertEquals( 1, attr.size() ); |
| } |
| |
| /** |
| * Check for DIR_SERVER_643 |
| * |
| * @throws NamingException |
| */ |
| public void testTwoDescriptionDirServer643() throws NamingException |
| { |
| // Change description attribute |
| Attributes attrs = new LockableAttributesImpl( true ); |
| Attribute attr = new LockableAttributeImpl( "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, DirContext.ADD_ATTRIBUTE, attrs ); |
| |
| // Verify, that attribute is still there, and is the only one |
| attrs = ctx.getAttributes( RDN ); |
| 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"). |
| * |
| * @throws NamingException |
| */ |
| public void testAddDuplicateValueToExistingAttribute() throws NamingException |
| { |
| // modify object classes, add a new value twice |
| Attribute ocls = new LockableAttributeImpl( "objectClass", "organizationalPerson" ); |
| ModificationItemImpl[] modItems = new ModificationItemImpl[2]; |
| modItems[0] = new ModificationItemImpl( DirContext.ADD_ATTRIBUTE, ocls ); |
| modItems[1] = new ModificationItemImpl( DirContext.ADD_ATTRIBUTE, ocls ); |
| try |
| { |
| ctx.modifyAttributes( RDN, 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 ); |
| ocls = attrs.get( "objectClass" ); |
| assertEquals( ocls.size(), 2 ); |
| 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"). |
| * |
| * @throws NamingException |
| */ |
| public void testAddDuplicateValueToNewAttribute() throws NamingException |
| { |
| // add the same description value twice |
| Attribute desc = new LockableAttributeImpl( "description", "another description value besides songwriter" ); |
| ModificationItemImpl[] modItems = new ModificationItemImpl[2]; |
| modItems[0] = new ModificationItemImpl( DirContext.ADD_ATTRIBUTE, desc ); |
| modItems[1] = new ModificationItemImpl( DirContext.ADD_ATTRIBUTE, desc ); |
| try |
| { |
| ctx.modifyAttributes( RDN, 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 ); |
| assertEquals( 1, attrs.get( "description" ).size() ); |
| } |
| |
| |
| /** |
| * Create an entry with a bad attribute : this should fail. |
| * |
| * @throws NamingException |
| */ |
| public void testAddUnexistingAttribute() throws NamingException |
| { |
| Hashtable env = new Hashtable(); |
| env.put( "java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory" ); |
| env.put( "java.naming.provider.url", "ldap://localhost:" + port + "/ou=system" ); |
| env.put( "java.naming.security.principal", "uid=admin,ou=system" ); |
| env.put( "java.naming.security.credentials", "secret" ); |
| env.put( "java.naming.security.authentication", "simple" ); |
| |
| ctx = new InitialLdapContext( env, null ); |
| assertNotNull( ctx ); |
| |
| // Create a third person with a voice attribute |
| Attributes attributes = this.getPersonAttributes( "Jackson", "Michael Jackson" ); |
| attributes.put( "voice", "He is bad ..." ); |
| |
| try |
| { |
| ctx.createSubcontext( "cn=Mickael Jackson", attributes ); |
| } |
| catch ( InvalidAttributeIdentifierException iaie ) |
| { |
| assertTrue( true ); |
| return; |
| } |
| |
| fail( "Should never reach this point" ); |
| } |
| |
| |
| /** |
| * Modu=ify the entry with a bad attribute : this should fail |
| * |
| * @throws NamingException |
| */ |
| public void testSearchBadAttribute() throws NamingException |
| { |
| // Add a not existing attribute |
| String newValue = "unbelievable"; |
| Attributes attrs = new LockableAttributesImpl( "voice", newValue ); |
| |
| try |
| { |
| ctx.modifyAttributes( RDN, DirContext.ADD_ATTRIBUTE, attrs ); |
| } |
| catch ( InvalidAttributeIdentifierException iaie ) |
| { |
| // 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. |
| */ |
| public void testAttributeValueMultiMofificationDIRSERVER_636() throws NamingException { |
| |
| // Create a person entry |
| Attributes attrs = getPersonAttributes("Bush", "Kate Bush"); |
| String rdn = "cn=Kate Bush"; |
| ctx.createSubcontext(rdn, attrs); |
| |
| // Add a decsription 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 LockableAttributeImpl("description"); |
| desc1.add(descriptions[0]); |
| desc1.add(descriptions[1]); |
| |
| ModificationItemImpl addModOp = new ModificationItemImpl( |
| DirContext.ADD_ATTRIBUTE, desc1); |
| |
| Attribute desc2 = new LockableAttributeImpl("description"); |
| desc2.add(descriptions[1]); |
| ModificationItemImpl delModOp = new ModificationItemImpl( |
| DirContext.REMOVE_ATTRIBUTE, desc2); |
| |
| ctx.modifyAttributes(rdn, new ModificationItemImpl[] { addModOp, |
| delModOp }); |
| |
| SearchControls sctls = new SearchControls(); |
| sctls.setSearchScope(SearchControls.SUBTREE_SCOPE); |
| String filter = "(sn=Bush)"; |
| String base = ""; |
| |
| // Check entry |
| NamingEnumeration enm = ctx.search(base, filter, sctls); |
| assertTrue(enm.hasMore()); |
| |
| while (enm.hasMore()) { |
| SearchResult sr = (SearchResult) enm.next(); |
| attrs = sr.getAttributes(); |
| Attribute desc = sr.getAttributes().get("description"); |
| assertNotNull(desc); |
| assertEquals(1, desc.size()); |
| assertTrue(desc.contains(descriptions[0])); |
| } |
| |
| // Remove the person entry |
| ctx.destroySubcontext(rdn); |
| } |
| |
| /** |
| * 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 |
| */ |
| /* |
| public void testDNAttributeMemberMofificationDIRSERVER_687() throws NamingException { |
| |
| // 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 } ); |
| } |
| catch ( AttributeModificationException ame ) |
| { |
| assertTrue( true ); |
| // Remove the person entry |
| ctx.destroySubcontext(rdn); |
| } |
| catch ( NamingException ne ) |
| { |
| assertTrue( true ); |
| // Remove the person entry |
| ctx.destroySubcontext(rdn); |
| } |
| |
| // Remove the person entry |
| ctx.destroySubcontext(rdn); |
| |
| fail(); |
| } |
| */ |
| |
| /** |
| * Try to modify an entry adding invalid number of values for a single-valued atribute |
| * @see http://issues.apache.org/jira/browse/DIRSERVER-614 |
| */ |
| public void testModifyAddWithInvalidNumberOfAttributeValues() throws NamingException |
| { |
| Attributes attrs = new LockableAttributesImpl(); |
| Attribute ocls = new LockableAttributeImpl( "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 LockableAttributesImpl(); |
| Attribute displayName = new LockableAttributeImpl( "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 ) |
| { |
| |
| } |
| } |
| } |