in interceptors/authz/src/main/java/org/apache/directory/server/core/authz/AciAuthorizationInterceptor.java [827:975]
public void modify( ModifyOperationContext modifyContext ) throws LdapException
{
Dn dn = modifyContext.getDn();
// Access the principal requesting the operation, and bypass checks if it is the admin
Entry entry = modifyContext.getEntry();
LdapPrincipal principal = modifyContext.getSession().getEffectivePrincipal();
Dn principalDn = principal.getDn();
// bypass authz code if we are disabled
if ( !directoryService.isAccessControlEnabled() )
{
next( modifyContext );
return;
}
List<Modification> mods = modifyContext.getModItems();
// bypass authz code but manage caches if operation is performed by the admin
if ( isPrincipalAnAdministrator( principalDn ) )
{
next( modifyContext );
Entry modifiedEntry = modifyContext.getAlteredEntry();
tupleCache.subentryModified( dn, mods, modifiedEntry );
groupCache.groupModified( dn, mods, entry, schemaManager );
return;
}
Set<String> userGroups = groupCache.getGroups( principalDn.getNormName() );
Collection<ACITuple> tuples = new HashSet<>();
addPerscriptiveAciTuples( modifyContext, tuples, dn, entry );
addEntryAciTuples( tuples, entry );
addSubentryAciTuples( modifyContext, tuples, dn, entry );
AciContext entryAciContext = new AciContext( schemaManager, modifyContext );
entryAciContext.setUserGroupNames( userGroups );
entryAciContext.setUserDn( principalDn );
entryAciContext.setAuthenticationLevel( principal.getAuthenticationLevel() );
entryAciContext.setEntryDn( dn );
entryAciContext.setMicroOperations( Collections.singleton( MicroOperation.MODIFY ) );
entryAciContext.setAciTuples( tuples );
entryAciContext.setEntry( entry );
engine.checkPermission( entryAciContext );
Collection<MicroOperation> perms;
Entry entryView = entry.clone();
for ( Modification mod : mods )
{
Attribute attr = mod.getAttribute();
switch ( mod.getOperation() )
{
case ADD_ATTRIBUTE:
perms = ADD_PERMS;
// If the attribute is being created with an initial value ...
if ( entry.get( attr.getId() ) == null )
{
AciContext attrAciContext = new AciContext( schemaManager, modifyContext );
attrAciContext.setUserGroupNames( userGroups );
attrAciContext.setUserDn( principalDn );
attrAciContext.setAuthenticationLevel( principal.getAuthenticationLevel() );
attrAciContext.setEntryDn( dn );
attrAciContext.setAttributeType( attr.getAttributeType() );
attrAciContext.setMicroOperations( perms );
attrAciContext.setAciTuples( tuples );
attrAciContext.setEntry( entry );
// ... we also need to check if adding the attribute is permitted
engine.checkPermission( attrAciContext );
}
break;
case REMOVE_ATTRIBUTE:
perms = REMOVE_PERMS;
Attribute entryAttr = entry.get( attr.getId() );
if ( ( entryAttr != null ) && ( entryAttr.size() == 1 ) )
{
// If there is only one value remaining in the attribute ...
// ... we also need to check if removing the attribute at all is permitted
AciContext aciContext = new AciContext( schemaManager, modifyContext );
aciContext.setUserGroupNames( userGroups );
aciContext.setUserDn( principalDn );
aciContext.setAuthenticationLevel( principal.getAuthenticationLevel() );
aciContext.setEntryDn( dn );
aciContext.setAttributeType( attr.getAttributeType() );
aciContext.setMicroOperations( perms );
aciContext.setAciTuples( tuples );
aciContext.setEntry( entry );
engine.checkPermission( aciContext );
}
break;
case REPLACE_ATTRIBUTE:
perms = REPLACE_PERMS;
break;
default:
throw new IllegalArgumentException( "Unexpected modify operation " + mod.getOperation() );
}
/**
* Update the entry view as the current modification is applied to the original entry.
* This is especially required for handling the MaxValueCount protected item. Number of
* values for an attribute after a modification should be known in advance in order to
* check permissions for MaxValueCount protected item. So during addition of the first
* value of an attribute it can be rejected if the permission denied due the the
* MaxValueCount protected item. This is not the perfect implementation as required by
* the specification because the system should reject the addition exactly on the right
* value of the attribute. However as we do not have that much granularity in our
* implementation (we consider an Attribute Addition itself a Micro Operation,
* not the individual Value Additions) we just handle this when the first value of an
* attribute is being checked for relevant permissions below.
*/
entryView = ServerEntryUtils.getTargetEntry( mod, entryView, schemaManager );
for ( Value value : attr )
{
AciContext aciContext = new AciContext( schemaManager, modifyContext );
aciContext.setUserGroupNames( userGroups );
aciContext.setUserDn( principalDn );
aciContext.setAuthenticationLevel( principal.getAuthenticationLevel() );
aciContext.setEntryDn( dn );
aciContext.setAttributeType( attr.getAttributeType() );
aciContext.setAttrValue( value );
aciContext.setMicroOperations( perms );
aciContext.setAciTuples( tuples );
aciContext.setEntry( entry );
aciContext.setEntryView( entryView );
engine.checkPermission( aciContext );
}
}
next( modifyContext );
Entry modifiedEntry = modifyContext.getAlteredEntry();
tupleCache.subentryModified( dn, mods, modifiedEntry );
groupCache.groupModified( dn, mods, entry, schemaManager );
}