blob: 883569dc038310fb6a70355947789af613953922 [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.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" );
}
}