blob: c8b93dcb3f77baf61fb780340ddb4b338a7fb84e [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.authz;
import static org.apache.directory.server.core.authz.AutzIntegUtils.addUserToGroup;
import static org.apache.directory.server.core.authz.AutzIntegUtils.createAccessControlSubentry;
import static org.apache.directory.server.core.authz.AutzIntegUtils.createUser;
import static org.apache.directory.server.core.authz.AutzIntegUtils.getAdminConnection;
import static org.apache.directory.server.core.authz.AutzIntegUtils.getConnectionAs;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.apache.directory.api.ldap.model.constants.SchemaConstants;
import org.apache.directory.api.ldap.model.entry.DefaultEntry;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException;
import org.apache.directory.api.ldap.model.name.Dn;
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 whether or not authorization rules for entry deletion works properly.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
@RunWith(FrameworkRunner.class)
@CreateDS(enableAccessControl = true, name = "DeleteAuthorizationIT")
public class DeleteAuthorizationIT extends AbstractLdapTestUnit
{
@Before
public void setService()
{
AutzIntegUtils.service = getService();
}
@After
public void closeConnections()
{
IntegrationUtils.closeConnections();
}
/**
* Checks if a simple entry (organizationalUnit) can be deleted from the DIT at an
* Rdn relative to ou=system by a specific non-admin user. The entry is first
* created using the admin account which can do anything without limitations.
* After creating the entry as the admin an attempt is made to delete it as the
* specified user.
*
* If a permission exception is encountered it is caught and false is returned,
* otherwise true is returned when the entry is created. The entry is deleted by the
* admin user after a delete failure to make sure the entry is deleted if subsequent
* calls are made to this method: the admin account is used to delete this test entry
* so permissions to delete are not required to delete it by the specified user.
*
* @param uid the unique identifier for the user (presumed to exist under ou=users,ou=system)
* @param password the password of this user
* @param entryRdn the relative Dn, relative to ou=system where entry creation then deletion is tested
* @return true if the entry can be created by the user at the specified location, false otherwise
* @throws Exception if there are problems conducting the test
*/
public boolean checkCanDeleteEntryAs( String uid, String password, String entryRdn ) throws Exception
{
Dn entryDn = new Dn( entryRdn + ",ou=system" );
// create the entry with the telephoneNumber attribute to compare
Entry testEntry = new DefaultEntry( entryDn );
testEntry.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
testEntry.add( SchemaConstants.OU_AT, "testou" );
LdapConnection adminConnection = getAdminConnection();
// create the entry as admin
adminConnection.add( testEntry );
Dn userName = new Dn( "uid=" + uid + ",ou=users,ou=system" );
// delete the newly created context as the user
LdapConnection userConnection = getConnectionAs( userName, password );
try
{
userConnection.delete( entryDn );
}
catch ( LdapNoPermissionException lnpe )
{
adminConnection.delete( entryDn );
return false;
}
return true;
}
/**
* Checks to make sure group membership based userClass works for delete operations.
*
* @throws Exception if the test encounters an error
*/
@Test
public void testGrantDeleteAdministrators() throws Exception
{
// create the non-admin user
createUser( "billyd", "billyd" );
// try a delete operation which should fail without any ACI
assertFalse( checkCanDeleteEntryAs( "billyd", "billyd", "ou=testou" ) );
// Gives grantRemove perm to all users in the Administrators group for
// entries and all attribute types and values
createAccessControlSubentry( "administratorAdd",
"{ " +
" identificationTag \"addAci\", " +
" precedence 14, " +
" authenticationLevel none, " +
" itemOrUserFirst userFirst: " +
" { " +
" userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " +
" userPermissions " +
" { " +
" { " +
" protectedItems {entry}, " +
" grantsAndDenials { grantRemove, grantBrowse } " +
" } " +
" } " +
" } " +
"}" );
// see if we can now delete that test entry which we could not before
// delete op should still fail since billd is not in the admin group
assertFalse( checkCanDeleteEntryAs( "billyd", "billyd", "ou=testou" ) );
// now add billyd to the Administrator group and try again
addUserToGroup( "billyd", "Administrators" );
// try a delete operation which should succeed with ACI and group membership change
assertTrue( checkCanDeleteEntryAs( "billyd", "billyd", "ou=testou" ) );
}
/**
* Checks to make sure name based userClass works for delete operations.
*
* @throws Exception if the test encounters an error
*/
@Test
public void testGrantDeleteByName() throws Exception
{
// create the non-admin user
createUser( "billyd", "billyd" );
// try a delete operation which should fail without any ACI
assertFalse( checkCanDeleteEntryAs( "billyd", "billyd", "ou=testou" ) );
// now add a subentry that enables user billyd to delete an entry below ou=system
createAccessControlSubentry( "billydAdd",
"{ " +
" identificationTag \"addAci\", " +
" precedence 14, " +
" authenticationLevel none, " +
" itemOrUserFirst userFirst: " +
" { " +
" userClasses { name { \"uid=billyd,ou=users,ou=system\" } }, " +
" userPermissions " +
" { " +
" { " + " protectedItems {entry}, " +
" grantsAndDenials { grantRemove, grantBrowse } " +
" } " +
" } " +
" } " +
"}" );
// should work now that billyd is authorized by name
assertTrue( checkCanDeleteEntryAs( "billyd", "billyd", "ou=testou" ) );
}
/**
* Checks to make sure subtree based userClass works for delete operations.
*
* @throws Exception if the test encounters an error
*/
@Test
public void testGrantDeleteBySubtree() throws Exception
{
// create the non-admin user
createUser( "billyd", "billyd" );
// try a delete operation which should fail without any ACI
assertFalse( checkCanDeleteEntryAs( "billyd", "billyd", "ou=testou" ) );
// now add a subentry that enables user billyd to delte an entry below ou=system
createAccessControlSubentry( "billyAddBySubtree",
"{ " +
" identificationTag \"addAci\", " +
" precedence 14, " +
" authenticationLevel none, " + " itemOrUserFirst userFirst: " +
" { " +
" userClasses " +
" { " + " subtree { { base \"ou=users,ou=system\" } } " +
" }, " +
" userPermissions " +
" { " +
" { " +
" protectedItems {entry}, " +
" grantsAndDenials { grantRemove, grantBrowse } " +
" } " +
" } " +
" } " +
"}" );
// should work now that billyd is authorized by the subtree userClass
assertTrue( checkCanDeleteEntryAs( "billyd", "billyd", "ou=testou" ) );
}
/**
* Checks to make sure <b>allUsers</b> userClass works for delete operations.
*
* @throws Exception if the test encounters an error
*/
@Test
public void testGrantDeleteAllUsers() throws Exception
{
// create the non-admin user
createUser( "billyd", "billyd" );
// try a delete operation which should fail without any ACI
assertFalse( checkCanDeleteEntryAs( "billyd", "billyd", "ou=testou" ) );
// now add a subentry that enables anyone to add an entry below ou=system
createAccessControlSubentry( "anybodyAdd",
"{ " +
" identificationTag \"addAci\", " +
" precedence 14, " +
" authenticationLevel none, " +
" itemOrUserFirst userFirst: " +
" { " +
" userClasses { allUsers }, " +
" userPermissions " +
" { " +
" { " +
" protectedItems {entry}, " +
" grantsAndDenials { grantRemove, grantBrowse } " +
" } " +
" } " +
" } " +
"}" );
// see if we can now delete that test entry which we could not before
// should work now with billyd now that all users are authorized
assertTrue( checkCanDeleteEntryAs( "billyd", "billyd", "ou=testou" ) );
}
}