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<Dn> userGroups = groupCache.getGroups( principalDn.getName() );
Collection<ACITuple> tuples = new HashSet<ACITuple>();
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 = null;
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 )
{
// If there is only one value remaining in the attribute ...
if ( entryAttr.size() == 1 )
{
// ... 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;
}
/**
* 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 );