| /* |
| * 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.core.operational; |
| |
| |
| 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 org.apache.directory.api.ldap.model.cursor.EntryCursor; |
| import org.apache.directory.api.ldap.model.entry.Attribute; |
| import org.apache.directory.api.ldap.model.entry.DefaultAttribute; |
| 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.Modification; |
| import org.apache.directory.api.ldap.model.entry.ModificationOperation; |
| import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException; |
| import org.apache.directory.api.ldap.model.message.SearchScope; |
| import org.apache.directory.ldap.client.api.LdapConnection; |
| import org.apache.directory.server.core.annotations.CreateDS; |
| import org.apache.directory.server.core.integ.AbstractLdapTestUnit; |
| import org.apache.directory.server.core.integ.FrameworkRunner; |
| import org.apache.directory.server.core.integ.IntegrationUtils; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| |
| /** |
| * Tests the methods on JNDI contexts that are analogous to entry modify |
| * operations in LDAP. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| @RunWith(FrameworkRunner.class) |
| @CreateDS(name = "OperationalAttributeServiceDS") |
| public class OperationalAttributeServiceIT extends AbstractLdapTestUnit |
| { |
| private static final String DN_KATE_BUSH = "cn=Kate Bush,ou=system"; |
| private static final String DN_KB = "cn=KB,ou=system"; |
| |
| private LdapConnection connection; |
| |
| |
| @Before |
| public void setup() throws Exception |
| { |
| connection = IntegrationUtils.getAdminConnection( getService() ); |
| |
| // add this entry before each test because we want |
| // to check that operational attributes are added |
| Entry entry = new DefaultEntry( |
| DN_KATE_BUSH, |
| "objectClass: top", |
| "objectClass: person", |
| "cn: Kate Bush", |
| "sn: Bush" ); |
| |
| connection.add( entry ); |
| } |
| |
| |
| @After |
| public void shutdown() throws Exception |
| { |
| // delete this entry after each test because we want |
| // to check that operational attributes are added |
| if ( connection.exists( DN_KATE_BUSH ) ) |
| { |
| connection.delete( DN_KATE_BUSH ); |
| } |
| |
| connection.close(); |
| } |
| |
| |
| @Test |
| public void testBinaryAttributeFilterExtension() throws Exception |
| { |
| Entry entry = new DefaultEntry( |
| "ou=test,ou=system", |
| "objectClass: top", |
| "objectClass: person", |
| "objectClass: organizationalPerson", |
| "objectClass: inetOrgPerson", |
| "ou", "test", |
| "cn", "test", |
| "sn", "test" ); |
| |
| connection.add( entry ); |
| |
| // test without turning on the property |
| Entry result = connection.lookup( "ou=test,ou=system" ); |
| Attribute ou = result.get( "ou" ); |
| Object value = ou.getString(); |
| assertTrue( value instanceof String ); |
| |
| // try jpegPhoto which should be binary automatically - use ou as control |
| byte[] keyValue = new byte[] |
| { ( byte ) 0xFF, ( byte ) 0xD8, ( byte ) 0xFF, ( byte ) 0xE0, 0x01, 0x02, 'J', 'F', 'I', 'F', 0x00, 0x45, |
| 0x23, 0x7d, 0x7f }; |
| |
| entry = new DefaultEntry( "ou=anothertest,ou=system", |
| "objectClass: top", |
| "objectClass: person", |
| "objectClass: organizationalPerson", |
| "objectClass: inetOrgPerson", |
| "ou: anotherTest", |
| "cn", "test", |
| "sn", "test", |
| "jpegPhoto", keyValue ); |
| |
| connection.add( entry ); |
| |
| Entry loadedEntry = connection.lookup( "ou=anothertest,ou=system" ); |
| |
| assertTrue( loadedEntry.contains( "ou", "anothertest" ) ); |
| assertTrue( loadedEntry.contains( "jpegPhoto", keyValue ) ); |
| } |
| |
| |
| @Test |
| public void testAddShouldAddOperationalOpAttrs() throws Exception |
| { |
| /* |
| * create ou=testing00,ou=system |
| */ |
| Entry entry = new DefaultEntry( |
| "ou=testing00,ou=system", |
| "objectClass: top", |
| "objectClass: organizationalUnit", |
| "ou", "testing00" ); |
| |
| connection.add( entry ); |
| |
| // search user attributes doesn't include op attrs |
| entry = connection.lookup( "ou=testing00,ou=system", "*" ); |
| |
| assertNotNull( entry ); |
| assertTrue( entry.contains( "ou", "testing00" ) ); |
| assertTrue( entry.contains( "objectClass", "top", "organizationalUnit" ) ); |
| |
| assertNull( entry.get( "createTimestamp" ) ); |
| assertNull( entry.get( "creatorsName" ) ); |
| |
| // search with '+' includes op attrs |
| entry = connection.lookup( "ou=testing00,ou=system", "*", "+" ); |
| |
| assertNotNull( entry.get( "ou" ) ); |
| assertNotNull( entry.get( "creatorsName" ) ); |
| assertNotNull( entry.get( "createTimestamp" ) ); |
| } |
| |
| |
| /** |
| * Checks to confirm that the system context root ou=system has the |
| * required operational attributes. Since this is created automatically |
| * on system database creation properties the create attributes must be |
| * specified. There are no interceptors in effect when this happens so |
| * we must test explicitly. |
| * |
| * @see <a href="http://nagoya.apache.org/jira/browse/DIREVE-57">DIREVE-57: |
| * ou=system does not contain operational attributes</a> |
| * |
| * @throws Exception on error |
| */ |
| @Test |
| public void testSystemContextRoot() throws Exception |
| { |
| EntryCursor responses = connection |
| .search( "ou=system", "(objectClass=*)", SearchScope.OBJECT, "*" ); |
| responses.next(); |
| Entry entry = responses.get(); |
| |
| // test to make sure op attribute do not occur - this is the control |
| assertNull( entry.get( "creatorsName" ) ); |
| assertNull( entry.get( "createTimestamp" ) ); |
| |
| responses.close(); |
| |
| // now we ask for all the op attributes and check to get them |
| responses = connection.search( "ou=system", "(objectClass=*)", SearchScope.OBJECT, "creatorsName", |
| "createTimestamp" ); |
| responses.next(); |
| entry = responses.get(); |
| |
| assertNotNull( entry.get( "creatorsName" ) ); |
| assertNotNull( entry.get( "createTimestamp" ) ); |
| |
| // We should not have any other operational Attribute |
| assertNull( entry.get( "entryUuid" ) ); |
| |
| responses.close(); |
| } |
| |
| |
| /** |
| * Test which confirms that all new users created under the user's dn |
| * (ou=users,ou=system) have the creatorsName set to the Dn of the new |
| * user even though the admin is creating the user. This is the basis |
| * for some authorization rules to protect passwords. |
| * |
| * NOTE THIS CHANGE WAS REVERTED SO WE ADAPTED THE TEST TO MAKE SURE THE |
| * CHANGE DOES NOT PERSIST! |
| * |
| * @see <a href="http://nagoya.apache.org/jira/browse/DIREVE-67">JIRA Issue DIREVE-67</a> |
| * |
| * @throws Exception on error |
| */ |
| @Test |
| public void testConfirmNonAdminUserDnIsCreatorsName() throws Exception |
| { |
| Entry entry = new DefaultEntry( |
| "uid=akarasulu,ou=users,ou=system", |
| "objectClass: top", |
| "objectClass: person", |
| "objectClass: organizationalPerson", |
| "objectClass: inetOrgPerson", |
| "ou: Engineering", |
| "ou: People", |
| "uid: akarasulu", |
| "l", "Bogusville", |
| "cn: Alex Karasulu", |
| "sn: Karasulu", |
| "givenName: Alex", |
| "mail: akarasulu@apache.org", |
| "telephoneNumber: +1 408 555 4798", |
| "facsimileTelephoneNumber: +1 408 555 9751", |
| "roomnumber: 4612", |
| "userPassword: test" ); |
| |
| connection.add( entry ); |
| |
| Entry result = connection.lookup( "uid=akarasulu,ou=users,ou=system", "creatorsName" ); |
| |
| assertFalse( "uid=akarasulu,ou=users,ou=system".equals( result.get( "creatorsName" ).getString() ) ); |
| } |
| |
| |
| /** |
| * Modify an entry and check whether attributes modifiersName and modifyTimestamp are present. |
| * |
| * @throws Exception on error |
| */ |
| @Test |
| public void testModifyShouldLeadToModifiersAttributes() throws Exception |
| { |
| Entry entry = connection.lookup( DN_KATE_BUSH, "modifiersName", "modifyTimestamp" ); |
| |
| assertNull( entry.get( "modifiersName" ) ); |
| assertNull( entry.get( "modifyTimestamp" ) ); |
| |
| Modification modifyOp = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, |
| new DefaultAttribute( "description", "Singer Songwriter" ) ); |
| |
| connection.modify( DN_KATE_BUSH, modifyOp ); |
| |
| entry = connection.lookup( DN_KATE_BUSH, "modifiersName", "modifyTimestamp" ); |
| |
| assertNotNull( entry.get( "modifiersName" ) ); |
| assertNotNull( entry.get( "modifyTimestamp" ) ); |
| } |
| |
| |
| /** |
| * Modify an entry and check whether attribute modifyTimestamp changes. |
| * |
| * @throws Exception on error |
| * @throws InterruptedException on error |
| */ |
| @Test |
| public void testModifyShouldChangeModifyTimestamp() throws Exception, InterruptedException |
| { |
| // Add attribute description to entry |
| Modification modifyAddOp = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, |
| new DefaultAttribute( "description", "an English singer, songwriter, musician" ) ); |
| |
| connection.modify( DN_KATE_BUSH, modifyAddOp ); |
| |
| // Determine modifyTimestamp |
| Entry entry = connection.lookup( DN_KATE_BUSH, "modifyTimestamp" ); |
| |
| Attribute modifyTimestamp = entry.get( "modifyTimestamp" ); |
| assertNotNull( modifyTimestamp ); |
| String oldTimestamp = modifyTimestamp.getString(); |
| |
| // Wait 2000 milliseconds |
| Thread.sleep( 2000 ); |
| |
| // Change value of attribute description |
| Modification modifyOp = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, |
| new DefaultAttribute( "description", "one of England's most successful solo female performers" ) ); |
| |
| connection.modify( DN_KATE_BUSH, modifyOp ); |
| |
| // Determine modifyTimestamp after modification |
| entry = connection.lookup( DN_KATE_BUSH, "modifyTimestamp" ); |
| |
| modifyTimestamp = entry.get( "modifyTimestamp" ); |
| assertNotNull( modifyTimestamp ); |
| String newTimestamp = modifyTimestamp.getString(); |
| |
| // assert the value has changed |
| assertFalse( oldTimestamp.equals( newTimestamp ) ); |
| } |
| |
| |
| /** |
| * Try to add modifiersName attribute to an entry |
| * this will succeed look at DIRSERVER-1416 |
| */ |
| @Test |
| public void testModifyOperationalAttributeAdd() throws Exception |
| { |
| // Add attribute description to entry |
| Modification modifyOp = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, |
| new DefaultAttribute( "modifiersName", "cn=Tori Amos,dc=example,dc=com" ) ); |
| |
| connection.modify( DN_KATE_BUSH, modifyOp ); |
| } |
| |
| |
| /** |
| * Try to remove creatorsName attribute from an entry. |
| * |
| * @throws Exception on error |
| */ |
| @Test(expected = LdapNoPermissionException.class) |
| public void testModifyOperationalAttributeRemove() throws Exception |
| { |
| Modification modifyOp = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, |
| new DefaultAttribute( "creatorsName" ) ); |
| |
| connection.modify( DN_KATE_BUSH, modifyOp ); |
| } |
| |
| |
| /** |
| * Try to replace creatorsName attribute on an entry. |
| * |
| * @throws Exception on error |
| */ |
| @Test(expected = LdapNoPermissionException.class) |
| public void testModifyOperationalAttributeReplace() throws Exception |
| { |
| Modification modifyOp = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, |
| new DefaultAttribute( "creatorsName", "cn=Tori Amos,dc=example,dc=com" ) ); |
| |
| connection.modify( DN_KATE_BUSH, modifyOp ); |
| } |
| |
| |
| /** |
| * Rename an entry and check whether attribute modifyTimestamp changes. |
| */ |
| @Test |
| public void testRenameShouldChangeModifyTimestamp() throws Exception, InterruptedException |
| { |
| Entry entry = connection.lookup( DN_KATE_BUSH, "*", "+" ); |
| |
| assertNotNull( entry.get( "creatorsName" ) ); |
| assertNotNull( entry.get( "createTimestamp" ) ); |
| assertNull( entry.get( "modifiersName" ) ); |
| assertNull( entry.get( "modifyTimestamp" ) ); |
| |
| connection.rename( DN_KATE_BUSH, "cn=KB" ); |
| |
| entry = connection.lookup( "cn=KB,ou=system", "*", "+" ); |
| |
| assertNotNull( entry.get( "creatorsName" ) ); |
| assertNotNull( entry.get( "createTimestamp" ) ); |
| assertNotNull( entry.get( "modifiersName" ) ); |
| assertNotNull( entry.get( "modifyTimestamp" ) ); |
| |
| connection.rename( DN_KB, "cn=Kate Bush" ); |
| } |
| |
| |
| /** |
| * Move an entry and check whether attribute modifyTimestamp changes. |
| */ |
| @Test |
| public void testMoveShouldChangeModifyTimestamp() throws Exception, InterruptedException |
| { |
| Entry entry = connection.lookup( DN_KATE_BUSH, "*", "+" ); |
| |
| assertNotNull( entry.get( "creatorsName" ) ); |
| assertNotNull( entry.get( "createTimestamp" ) ); |
| assertNull( entry.get( "modifiersName" ) ); |
| assertNull( entry.get( "modifyTimestamp" ) ); |
| |
| connection.move( DN_KATE_BUSH, "ou=users,ou=system" ); |
| |
| entry = connection.lookup( "cn=Kate Bush,ou=users,ou=system", "*", "+" ); |
| |
| assertNotNull( entry.get( "creatorsName" ) ); |
| assertNotNull( entry.get( "createTimestamp" ) ); |
| assertNotNull( entry.get( "modifiersName" ) ); |
| assertNotNull( entry.get( "modifyTimestamp" ) ); |
| |
| connection.delete( "cn=Kate Bush,ou=users,ou=system" ); |
| } |
| |
| |
| /** |
| * MoveAndRename an entry and check whether attribute modifyTimestamp changes. |
| */ |
| @Test |
| public void testMoveAndRenameShouldChangeModifyTimestamp() throws Exception, InterruptedException |
| { |
| Entry entry = connection.lookup( DN_KATE_BUSH, "*", "+" ); |
| |
| assertNotNull( entry.get( "creatorsName" ) ); |
| assertNotNull( entry.get( "createTimestamp" ) ); |
| assertNull( entry.get( "modifiersName" ) ); |
| assertNull( entry.get( "modifyTimestamp" ) ); |
| |
| connection.moveAndRename( DN_KATE_BUSH, "cn=KB,ou=users,ou=system" ); |
| |
| entry = connection.lookup( "cn=KB,ou=users,ou=system", "*", "+" ); |
| |
| assertNotNull( entry.get( "creatorsName" ) ); |
| assertNotNull( entry.get( "createTimestamp" ) ); |
| assertNotNull( entry.get( "modifiersName" ) ); |
| assertNotNull( entry.get( "modifyTimestamp" ) ); |
| |
| connection.delete( "cn=KB,ou=users,ou=system" ); |
| } |
| } |