You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2011/10/20 21:42:13 UTC
svn commit: r1187013 [6/12] - in /directory/apacheds/branches/apacheds-txns:
./ all/ apache-felix/ apache-felix/bundle/ apache-felix/src/
apache-felix/src/main/ apache-felix/src/main/resources/ core-annotations/
core-annotations/src/main/java/org/apach...
Added: directory/apacheds/branches/apacheds-txns/interceptors/admin/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/interceptors/admin/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java?rev=1187013&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/interceptors/admin/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java (added)
+++ directory/apacheds/branches/apacheds-txns/interceptors/admin/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java Thu Oct 20 19:41:49 2011
@@ -0,0 +1,1515 @@
+/*
+ * 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.admin;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import javax.naming.directory.SearchControls;
+
+import org.apache.directory.server.constants.ServerDNConstants;
+import org.apache.directory.server.core.shared.DefaultCoreSession;
+import org.apache.directory.server.core.api.CoreSession;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.LdapPrincipal;
+import org.apache.directory.server.core.api.administrative.AccessControlAAP;
+import org.apache.directory.server.core.api.administrative.AccessControlAdministrativePoint;
+import org.apache.directory.server.core.api.administrative.AccessControlIAP;
+import org.apache.directory.server.core.api.administrative.AccessControlSAP;
+import org.apache.directory.server.core.api.administrative.AdministrativePoint;
+import org.apache.directory.server.core.api.administrative.CollectiveAttributeAAP;
+import org.apache.directory.server.core.api.administrative.CollectiveAttributeAdministrativePoint;
+import org.apache.directory.server.core.api.administrative.CollectiveAttributeIAP;
+import org.apache.directory.server.core.api.administrative.CollectiveAttributeSAP;
+import org.apache.directory.server.core.api.administrative.SubschemaAAP;
+import org.apache.directory.server.core.api.administrative.SubschemaAdministrativePoint;
+import org.apache.directory.server.core.api.administrative.SubschemaSAP;
+import org.apache.directory.server.core.api.administrative.TriggerExecutionAAP;
+import org.apache.directory.server.core.api.administrative.TriggerExecutionAdministrativePoint;
+import org.apache.directory.server.core.api.administrative.TriggerExecutionIAP;
+import org.apache.directory.server.core.api.administrative.TriggerExecutionSAP;
+import org.apache.directory.server.core.api.entry.ClonedServerEntry;
+import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
+import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
+import org.apache.directory.server.core.api.interceptor.Interceptor;
+import org.apache.directory.server.core.api.interceptor.NextInterceptor;
+import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
+import org.apache.directory.server.core.api.partition.PartitionNexus;
+import org.apache.directory.shared.ldap.model.constants.AuthenticationLevel;
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.model.entry.Attribute;
+import org.apache.directory.shared.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.Modification;
+import org.apache.directory.shared.ldap.model.entry.Value;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.shared.ldap.model.exception.LdapNoSuchAttributeException;
+import org.apache.directory.shared.ldap.model.exception.LdapOperationException;
+import org.apache.directory.shared.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.PresenceNode;
+import org.apache.directory.shared.ldap.model.message.AliasDerefMode;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.subtree.AdministrativeRole;
+import org.apache.directory.shared.ldap.util.tree.DnNode;
+import org.apache.directory.shared.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An interceptor to manage the Administrative model
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AdministrativePointInterceptor extends BaseInterceptor
+{
+ /** A {@link Logger} for this class */
+ private static final Logger LOG = LoggerFactory.getLogger( AdministrativePointInterceptor.class );
+
+ /**
+ * Speedup for logs
+ */
+ private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+ /** A reference to the nexus for direct backend operations */
+ private PartitionNexus nexus;
+
+ /** The possible roles */
+ private static final Set<String> ROLES = new HashSet<String>();
+
+ // Initialize the ROLES field
+ static
+ {
+ ROLES.add( Strings.toLowerCase( SchemaConstants.AUTONOMOUS_AREA ) );
+ ROLES.add( SchemaConstants.AUTONOMOUS_AREA_OID );
+ ROLES.add( Strings.toLowerCase( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ) );
+ ROLES.add( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
+ ROLES.add( Strings.toLowerCase( SchemaConstants.ACCESS_CONTROL_INNER_AREA ) );
+ ROLES.add( SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID );
+ ROLES.add( Strings.toLowerCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ) );
+ ROLES.add( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
+ ROLES.add( Strings.toLowerCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA ) );
+ ROLES.add( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID );
+ ROLES.add( Strings.toLowerCase( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA ) );
+ ROLES.add( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID );
+ ROLES.add( Strings.toLowerCase( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ) );
+ ROLES.add( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
+ ROLES.add( Strings.toLowerCase( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA ) );
+ ROLES.add( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID );
+ }
+
+ /** A Map to associate a role with it's OID */
+ private static final Map<String, String> ROLES_OID = new HashMap<String, String>();
+
+ // Initialize the roles/oid map
+ static
+ {
+ ROLES_OID.put( Strings.toLowerCase( SchemaConstants.AUTONOMOUS_AREA ), SchemaConstants.AUTONOMOUS_AREA_OID );
+ ROLES_OID.put( Strings.toLowerCase( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ),
+ SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
+ ROLES_OID.put( Strings.toLowerCase( SchemaConstants.ACCESS_CONTROL_INNER_AREA ),
+ SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID );
+ ROLES_OID.put( Strings.toLowerCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ),
+ SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
+ ROLES_OID.put( Strings.toLowerCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA ),
+ SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID );
+ ROLES_OID.put( Strings.toLowerCase( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA ),
+ SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID );
+ ROLES_OID.put( Strings.toLowerCase( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ),
+ SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
+ ROLES_OID.put( Strings.toLowerCase( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA ),
+ SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID );
+ }
+
+ /** The possible inner area roles */
+ private static final Set<String> INNER_AREA_ROLES = new HashSet<String>();
+
+ static
+ {
+ INNER_AREA_ROLES.add( Strings.toLowerCase( SchemaConstants.ACCESS_CONTROL_INNER_AREA ) );
+ INNER_AREA_ROLES.add( SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID );
+ INNER_AREA_ROLES.add( Strings.toLowerCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA ) );
+ INNER_AREA_ROLES.add( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID );
+ INNER_AREA_ROLES.add( Strings.toLowerCase( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA ) );
+ INNER_AREA_ROLES.add( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID );
+ }
+
+ /** The possible specific area roles */
+ private static final Set<String> SPECIFIC_AREA_ROLES = new HashSet<String>();
+
+ static
+ {
+ SPECIFIC_AREA_ROLES.add( Strings.toLowerCase( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ) );
+ SPECIFIC_AREA_ROLES.add( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
+ SPECIFIC_AREA_ROLES.add( Strings.toLowerCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ) );
+ SPECIFIC_AREA_ROLES.add( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
+ SPECIFIC_AREA_ROLES.add( Strings.toLowerCase( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA ) );
+ SPECIFIC_AREA_ROLES.add( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID );
+ SPECIFIC_AREA_ROLES.add( Strings.toLowerCase( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ) );
+ SPECIFIC_AREA_ROLES.add( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
+ }
+
+ /** A lock to guarantee the AP cache consistency */
+ private ReentrantReadWriteLock mutex = new ReentrantReadWriteLock();
+
+ /**
+ * Get a read-lock on the AP cache.
+ * No read operation can be done on the AP cache if this
+ * method is not called before.
+ */
+ public void lockRead()
+ {
+ mutex.readLock().lock();
+ }
+
+
+ /**
+ * Get a write-lock on the AP cache.
+ * No write operation can be done on the apCache if this
+ * method is not called before.
+ */
+ public void lockWrite()
+ {
+ mutex.writeLock().lock();
+ }
+
+
+ /**
+ * Release the read-write lock on the AP cache.
+ * This method must be called after having read or modified the
+ * AP cache
+ */
+ public void unlock()
+ {
+ if ( mutex.isWriteLockedByCurrentThread() )
+ {
+ mutex.writeLock().unlock();
+ }
+ else
+ {
+ mutex.readLock().unlock();
+ }
+ }
+
+
+ /**
+ * Create the list of AP for a given entry
+ */
+ private void createAdministrativePoints( Attribute adminPoint, Dn dn, String uuid ) throws LdapException
+ {
+ if ( isAAP( adminPoint ) )
+ {
+ // The AC AAP
+ AccessControlAdministrativePoint acAap = new AccessControlAAP( dn, uuid );
+ directoryService.getAccessControlAPCache().add( dn, acAap );
+
+ // The CA AAP
+ CollectiveAttributeAdministrativePoint caAap = new CollectiveAttributeAAP( dn, uuid );
+ directoryService.getCollectiveAttributeAPCache().add( dn, caAap );
+
+ // The TE AAP
+ TriggerExecutionAdministrativePoint teAap = new TriggerExecutionAAP( dn, uuid );
+ directoryService.getTriggerExecutionAPCache().add( dn, teAap );
+
+ // The SS AAP
+ SubschemaAdministrativePoint ssAap = new SubschemaAAP( dn, uuid );
+ directoryService.getSubschemaAPCache().add( dn, ssAap );
+
+ // TODO : Here, we have to update the children, removing any
+ // reference to any other underlying AP
+
+ // If it's an AAP, we can get out immediately
+ return;
+ }
+
+ for ( Value<?> value : adminPoint )
+ {
+ String role = value.getString();
+
+ // Deal with AccessControl AP
+ if ( isAccessControlSpecificRole( role ) )
+ {
+ AccessControlAdministrativePoint sap = new AccessControlSAP( dn, uuid );
+ directoryService.getAccessControlAPCache().add( dn, sap );
+
+ // TODO : Here, we have to update the children, removing any
+ // reference to any other underlying AccessControl IAP or SAP
+
+ continue;
+ }
+
+ if ( isAccessControlInnerRole( role ) )
+ {
+ AccessControlAdministrativePoint iap = new AccessControlIAP( dn, uuid );
+ directoryService.getAccessControlAPCache().add( dn, iap );
+
+ continue;
+ }
+
+ // Deal with CollectiveAttribute AP
+ if ( isCollectiveAttributeSpecificRole( role ) )
+ {
+ CollectiveAttributeAdministrativePoint sap = new CollectiveAttributeSAP( dn, uuid );
+ directoryService.getCollectiveAttributeAPCache().add( dn, sap );
+
+ // TODO : Here, we have to update the children, removing any
+ // reference to any other underlying CollectiveAttribute IAP or SAP
+
+ continue;
+ }
+
+ if ( isCollectiveAttributeInnerRole( role ) )
+ {
+ CollectiveAttributeAdministrativePoint iap = new CollectiveAttributeIAP( dn, uuid );
+ directoryService.getCollectiveAttributeAPCache().add( dn, iap );
+
+ continue;
+ }
+
+ // Deal with SubSchema AP
+ if ( isSubschemaSpecficRole( role ) )
+ {
+ SubschemaAdministrativePoint sap = new SubschemaSAP( dn, uuid );
+ directoryService.getSubschemaAPCache().add( dn, sap );
+
+ // TODO : Here, we have to update the children, removing any
+ // reference to any other underlying Subschema IAP or SAP
+
+ continue;
+ }
+
+ // Deal with TriggerExecution AP
+ if ( isTriggerExecutionSpecificRole( role ) )
+ {
+ TriggerExecutionAdministrativePoint sap = new TriggerExecutionSAP( dn, uuid );
+ directoryService.getTriggerExecutionAPCache().add( dn, sap );
+
+ // TODO : Here, we have to update the children, removing any
+ // reference to any other underlying TriggerExecution IAP or SAP
+
+ continue;
+ }
+
+ if ( isTriggerExecutionInnerRole( role ) )
+ {
+ TriggerExecutionAdministrativePoint iap = new TriggerExecutionIAP( dn, uuid );
+ directoryService.getTriggerExecutionAPCache().add( dn, iap );
+
+ continue;
+ }
+ }
+
+ return;
+ }
+
+
+ /**
+ * Update the cache clones with the added roles
+ */
+ private void addRole( String role, Dn dn, String uuid, DnNode<AccessControlAdministrativePoint> acapCache,
+ DnNode<CollectiveAttributeAdministrativePoint> caapCache, DnNode<TriggerExecutionAdministrativePoint> teapCache,
+ DnNode<SubschemaAdministrativePoint> ssapCache ) throws LdapException
+ {
+ // Deal with Autonomous AP : create the 4 associated SAP/AAP
+ if ( isAutonomousAreaRole( role ) )
+ {
+ // The AC AAP
+ AccessControlAdministrativePoint acAap = new AccessControlAAP( dn, uuid );
+ acapCache.add( dn, acAap );
+
+ // The CA AAP
+ CollectiveAttributeAdministrativePoint caAap = new CollectiveAttributeAAP( dn, uuid );
+ caapCache.add( dn, caAap );
+
+ // The TE AAP
+ TriggerExecutionAdministrativePoint teAap = new TriggerExecutionAAP( dn, uuid );
+ teapCache.add( dn, teAap );
+
+ // The SS AAP
+ SubschemaAdministrativePoint ssAap = new SubschemaAAP( dn, uuid );
+ ssapCache.add( dn, ssAap );
+
+ // If it's an AAP, we can get out immediately
+ return;
+ }
+
+ // Deal with AccessControl AP
+ if ( isAccessControlSpecificRole( role ) )
+ {
+ AccessControlAdministrativePoint sap = new AccessControlSAP( dn, uuid );
+ acapCache.add( dn, sap );
+
+ return;
+ }
+
+ if ( isAccessControlInnerRole( role ) )
+ {
+ AccessControlAdministrativePoint iap = new AccessControlIAP( dn, uuid );
+ acapCache.add( dn, iap );
+
+ return;
+ }
+
+ // Deal with CollectiveAttribute AP
+ if ( isCollectiveAttributeSpecificRole( role ) )
+ {
+ CollectiveAttributeAdministrativePoint sap = new CollectiveAttributeSAP( dn, uuid );
+ caapCache.add( dn, sap );
+
+ return;
+ }
+
+ if ( isCollectiveAttributeInnerRole( role ) )
+ {
+ CollectiveAttributeAdministrativePoint iap = new CollectiveAttributeIAP( dn, uuid );
+ caapCache.add( dn, iap );
+
+ return;
+ }
+
+ // Deal with SubSchema AP
+ if ( isSubschemaSpecficRole( role ) )
+ {
+ SubschemaAdministrativePoint sap = new SubschemaSAP( dn, uuid );
+ ssapCache.add( dn, sap );
+
+ return;
+ }
+
+ // Deal with TriggerExecution AP
+ if ( isTriggerExecutionSpecificRole( role ) )
+ {
+ TriggerExecutionAdministrativePoint sap = new TriggerExecutionSAP( dn, uuid );
+ teapCache.add( dn, sap );
+
+ return;
+ }
+
+ if ( isTriggerExecutionInnerRole( role ) )
+ {
+ TriggerExecutionAdministrativePoint iap = new TriggerExecutionIAP( dn, uuid );
+ teapCache.add( dn, iap );
+
+ return;
+ }
+ }
+
+
+
+
+ /**
+ * Update the cache clones with the added roles
+ */
+ private void delRole( String role, Dn dn, String uuid, DnNode<AccessControlAdministrativePoint> acapCache,
+ DnNode<CollectiveAttributeAdministrativePoint> caapCache, DnNode<TriggerExecutionAdministrativePoint> teapCache,
+ DnNode<SubschemaAdministrativePoint> ssapCache ) throws LdapException
+ {
+ // Deal with Autonomous AP : remove the 4 associated SAP/AAP
+ if ( isAutonomousAreaRole( role ) )
+ {
+ // The AC AAP
+ acapCache.remove( dn );
+
+ // The CA AAP
+ caapCache.remove( dn );
+
+ // The TE AAP
+ teapCache.remove( dn );
+
+ // The SS AAP
+ ssapCache.remove( dn );
+
+ return;
+ }
+
+ // Deal with AccessControl AP
+ if ( isAccessControlSpecificRole( role ) || isAccessControlInnerRole( role ) )
+ {
+ acapCache.remove( dn );
+
+ return;
+ }
+
+ // Deal with CollectiveAttribute AP
+ if ( isCollectiveAttributeSpecificRole( role ) || isCollectiveAttributeInnerRole( role ) )
+ {
+ caapCache.remove( dn );
+
+ return;
+ }
+
+ // Deal with SubSchema AP
+ if ( isSubschemaSpecficRole( role ) )
+ {
+ ssapCache.remove( dn );
+
+ return;
+ }
+
+ // Deal with TriggerExecution AP
+ if ( isTriggerExecutionSpecificRole( role ) || isTriggerExecutionInnerRole( role ) )
+ {
+ teapCache.remove( dn );
+
+ return;
+ }
+ }
+
+
+ private AdministrativePoint getParent( AdministrativePoint ap, List<AdministrativePoint> aps,
+ AdministrativeRole role, DnNode<List<AdministrativePoint>> currentNode )
+ {
+ AdministrativePoint parent = null;
+
+ for ( AdministrativePoint adminPoint : aps )
+ {
+ if ( adminPoint.isAutonomous() || ( adminPoint.getRole() == ap.getRole() ) )
+ {
+ // Same role or AP : this is the parent
+ return adminPoint;
+ }
+ else if ( adminPoint.getRole() == role )
+ {
+ parent = adminPoint;
+ }
+ }
+
+ if ( parent != null )
+ {
+ return parent;
+ }
+
+ // We have to go down one level
+ if ( currentNode.hasParent() )
+ {
+ return findParent( ap, currentNode );
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ /**
+ * Find the parent for the given administrative point. If the AP is an AAP, the parent will be the closest
+ * AAP or the closest SAP. If we have a SAP between the added AAP and a AAP, then
+ */
+ private AdministrativePoint findParent( AdministrativePoint ap, DnNode<List<AdministrativePoint>> currentNode )
+ {
+ List<AdministrativePoint> aps = currentNode.getElement();
+
+ if ( aps != null )
+ {
+ // Check if the current element is a valid parent
+ switch ( ap.getRole() )
+ {
+ case AutonomousArea:
+ AdministrativePoint currentAp = aps.get( 0 );
+
+ if ( currentAp.isAutonomous() )
+ {
+ return currentAp;
+ }
+ else
+ {
+ // We have to go down one level, as an AAP
+ // must have another AAP as a parent
+ if ( currentNode.hasParent() )
+ {
+ return findParent( ap, currentNode );
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ case AccessControlInnerArea:
+ return getParent( ap, aps, AdministrativeRole.AccessControlSpecificArea, currentNode );
+
+ case CollectiveAttributeInnerArea:
+ return getParent( ap, aps, AdministrativeRole.CollectiveAttributeSpecificArea, currentNode );
+
+ case TriggerExecutionInnerArea:
+ return getParent( ap, aps, AdministrativeRole.TriggerExecutionSpecificArea, currentNode );
+
+ case AccessControlSpecificArea:
+ return getParent( ap, aps, AdministrativeRole.AccessControlSpecificArea, currentNode );
+
+ case CollectiveAttributeSpecificArea:
+ return getParent( ap, aps, AdministrativeRole.CollectiveAttributeSpecificArea, currentNode );
+
+ case SubSchemaSpecificArea:
+ return getParent( ap, aps, AdministrativeRole.SubSchemaSpecificArea, currentNode );
+
+ case TriggerExecutionSpecificArea:
+ return getParent( ap, aps, AdministrativeRole.TriggerExecutionSpecificArea, currentNode );
+
+ default:
+ return null;
+ }
+ }
+ else
+ {
+ if ( currentNode.hasParent() )
+ {
+ return findParent( ap, currentNode.getParent() );
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+
+ /**
+ * Check if we can safely add a role. If it's an AAP, we have to be sure that
+ * it's the only role present in the AT.
+ */
+ private void checkAddRole( Value<?> role, Attribute adminPoint, Dn dn ) throws LdapException
+ {
+ String roleStr = Strings.toLowerCase( Strings.trim( role.getString() ) );
+
+ // Check that the added AdministrativeRole is valid
+ if ( !ROLES.contains( roleStr ) )
+ {
+ String message = "Cannot add the given role, it's not a valid one :" + role;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+
+ // If we are trying to add an AAP, we have to check that
+ // it's the only role in the AdminPoint AT
+ if ( isAutonomousAreaRole( roleStr ) )
+ {
+ if ( adminPoint.size() > 1 )
+ {
+ String message = "Cannot add an Autonomous Administratve Point when some other roles are added : "
+ + adminPoint;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ else
+ {
+ // Fine : we only have one AAP
+ return;
+ }
+ }
+
+ // Check that we don't have already an AAP in the AdminPoint AT when we try to
+ // add a role
+ if ( adminPoint.contains( SchemaConstants.AUTONOMOUS_AREA ) )
+ {
+ String message = "Cannot add a role when an Autonomous Administratve Point is already present : "
+ + adminPoint;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+
+ // check that we can't mix Inner and Specific areas
+ checkInnerSpecificMix( roleStr, adminPoint );
+
+ // Check that we don't add an IAP with no parent. The IAP must be added under
+ // either a AAP, or a SAP/IAP within the same family
+ if ( isIAP( roleStr ) )
+ {
+ checkIAPHasParent( roleStr, adminPoint, dn );
+ }
+ }
+
+
+ /**
+ * Check if we can safely delete a role
+ */
+ private void checkDelRole( Value<?> role, Attribute adminPoint, Dn dn ) throws LdapException
+ {
+ String roleStr = Strings.toLowerCase( Strings.trim( role.getString() ) );
+
+ // Check that the removed AdministrativeRole is valid
+ if ( !ROLES.contains( roleStr ) )
+ {
+ String message = "Cannot delete the given role, it's not a valid one :" + role;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+
+ // Now we are trying to delete an Administrative point. We have to check that
+ // we only have one role if the deleted role is an AAP
+ if ( isAutonomousAreaRole( roleStr ) )
+ {
+ // We know have to check that removing the AAP, we will not
+ // left any pending IAP. We should check for the 3 potential IAPs :
+ // AccessControl, CollectiveAttribute and TriggerExecution.
+ // If the removed AP has a parent, no need to go any further :
+ // the children IAPs will depend on this parent.
+
+ // Process the ACs
+ DnNode<AccessControlAdministrativePoint> acAps = directoryService.getAccessControlAPCache();
+
+ if ( !acAps.hasParent( dn ) )
+ {
+ // No parent, check for any IAP
+ List<AccessControlAdministrativePoint> children = acAps.getDescendantElements( dn );
+
+ for ( AccessControlAdministrativePoint child : children )
+ {
+ if ( child.isInner() )
+ {
+ // Ok, we are dead : the IAP will remain with no parent.
+ String message = "Cannot delete the given role, the " + child.getDn() + " AccessControl IAP will remain orphan";
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ }
+ }
+
+ // Process the CAs
+ DnNode<CollectiveAttributeAdministrativePoint> caAps = directoryService.getCollectiveAttributeAPCache();
+
+ if ( !acAps.hasParent( dn ) )
+ {
+ // No parent, check for any IAP
+ List<CollectiveAttributeAdministrativePoint> children = caAps.getDescendantElements( dn );
+
+ for ( CollectiveAttributeAdministrativePoint child : children )
+ {
+ if ( child.isInner() )
+ {
+ // Ok, we are dead : the IAP will remain with no parent.
+ String message = "Cannot delete the given role, the " + child.getDn() + " CollectiveAttribute IAP will remain orphan";
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ }
+ }
+
+ // Process the TEs
+ DnNode<TriggerExecutionAdministrativePoint> teAps = directoryService.getTriggerExecutionAPCache();
+
+ if ( !acAps.hasParent( dn ) )
+ {
+ // No parent, check for any IAP
+ List<TriggerExecutionAdministrativePoint> children = teAps.getDescendantElements( dn );
+
+ for ( TriggerExecutionAdministrativePoint child : children )
+ {
+ if ( child.isInner() )
+ {
+ // Ok, we are dead : the IAP will remain with no parent.
+ String message = "Cannot delete the given role, the " + child.getDn() + " TriggerExecution IAP will remain orphan";
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Creates an Administrative service interceptor.
+ */
+ public AdministrativePointInterceptor()
+ {
+ }
+
+
+ //-------------------------------------------------------------------------------------------
+ // Helper methods
+ //-------------------------------------------------------------------------------------------
+ private List<Entry> getAdministrativePoints() throws LdapException
+ {
+ List<Entry> entries = new ArrayList<Entry>();
+
+ Dn adminDn = new Dn( schemaManager, ServerDNConstants.ADMIN_SYSTEM_DN );
+
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+ controls.setReturningAttributes( new String[]
+ { SchemaConstants.ADMINISTRATIVE_ROLE_AT, SchemaConstants.ENTRY_UUID_AT } );
+
+ // Search for all the adminstrativePoints in the base
+ ExprNode filter = new PresenceNode( ADMINISTRATIVE_ROLE_AT );
+
+ CoreSession adminSession = new DefaultCoreSession( new LdapPrincipal( schemaManager, adminDn, AuthenticationLevel.STRONG ),
+ directoryService );
+
+ SearchOperationContext searchOperationContext = new SearchOperationContext( adminSession, Dn.ROOT_DSE, filter,
+ controls );
+
+ searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
+
+ EntryFilteringCursor results = nexus.search( searchOperationContext );
+
+ try
+ {
+ while ( results.next() )
+ {
+ Entry entry = results.get();
+
+ entries.add( entry );
+ }
+
+ results.close();
+ }
+ catch ( Exception e )
+ {
+ throw new LdapOperationException( e.getMessage(), e );
+ }
+
+ return entries;
+ }
+
+
+ /**
+ * Tells if a given role is a valid administrative role. We check the lower cased
+ * and trimmed value, and also the OID value.
+ */
+ private boolean isValidRole( String role )
+ {
+ return ROLES.contains( Strings.toLowerCase( Strings.trim( role ) ) );
+ }
+
+
+ /**
+ * Update The Administrative Points cache, adding the given AdminPoints
+ */
+ private void addAdminPointCache( List<Entry> adminPointEntries ) throws LdapException
+ {
+ for ( Entry adminPointEntry : adminPointEntries )
+ {
+ // update the cache
+ Dn dn = adminPointEntry.getDn();
+
+ String uuid = adminPointEntry.get( ENTRY_UUID_AT ).getString();
+ Attribute adminPoint = adminPointEntry.get( ADMINISTRATIVE_ROLE_AT );
+
+ createAdministrativePoints( adminPoint, dn, uuid );
+ }
+ }
+
+
+ /**
+ * Update The Administrative Points cache, removing the given AdminPoint
+ */
+ private void deleteAdminPointCache( Attribute adminPoint, DeleteOperationContext deleteContext )
+ throws LdapException
+ {
+ Dn dn = deleteContext.getDn();
+
+ // Remove the APs in the AP cache
+ for ( Value<?> value : adminPoint )
+ {
+ String role = value.getString();
+
+ // Deal with Autonomous AP : delete the 4 associated SAP/AAP
+ if ( isAutonomousAreaRole( role ) )
+ {
+ // The AC AAP
+ directoryService.getAccessControlAPCache().remove( dn );
+
+ // The CA AAP
+ directoryService.getCollectiveAttributeAPCache().remove( dn );
+
+ // The TE AAP
+ directoryService.getTriggerExecutionAPCache().remove( dn );
+
+ // The SS AAP
+ directoryService.getSubschemaAPCache().remove( dn );
+
+ // If it's an AAP, we can get out immediately
+ return;
+ }
+
+ // Deal with AccessControl AP
+ if ( isAccessControlSpecificRole( role ) || isAccessControlInnerRole( role ) )
+ {
+ directoryService.getAccessControlAPCache().remove( dn );
+
+ continue;
+ }
+
+ // Deal with CollectveAttribute AP
+ if ( isCollectiveAttributeSpecificRole( role ) || isCollectiveAttributeInnerRole( role ) )
+ {
+ directoryService.getCollectiveAttributeAPCache().remove( dn );
+
+ continue;
+ }
+
+
+ // Deal with SubSchema AP
+ if ( isSubschemaSpecficRole( role ) )
+ {
+ directoryService.getSubschemaAPCache().remove( dn );
+
+ continue;
+ }
+
+ // Deal with TriggerExecution AP
+ if ( isTriggerExecutionSpecificRole( role ) || isTriggerExecutionInnerRole( role ))
+ {
+ directoryService.getTriggerExecutionAPCache().remove( dn );
+
+ continue;
+ }
+ }
+ }
+
+
+ /**
+ * Tells if the role is an AC IAP
+ */
+ private boolean isAccessControlInnerRole( String role )
+ {
+ return role.equalsIgnoreCase( SchemaConstants.ACCESS_CONTROL_INNER_AREA ) ||
+ role.equals( SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID );
+ }
+
+
+ /**
+ * Tells if the role is an AC SAP
+ */
+ private boolean isAccessControlSpecificRole( String role )
+ {
+ return role.equalsIgnoreCase( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ) ||
+ role.equals( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
+ }
+
+
+ /**
+ * Tells if the role is a CA IAP
+ */
+ private boolean isCollectiveAttributeInnerRole( String role )
+ {
+ return role.equalsIgnoreCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA ) ||
+ role.equals( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID );
+ }
+
+
+ /**
+ * Tells if the role is a CA SAP
+ */
+ private boolean isCollectiveAttributeSpecificRole( String role )
+ {
+ return role.equalsIgnoreCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ) ||
+ role.equals( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
+ }
+
+
+ /**
+ * Tells if the role is a TE IAP
+ */
+ private boolean isTriggerExecutionInnerRole( String role )
+ {
+ return role.equalsIgnoreCase( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA ) ||
+ role.equals( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID );
+ }
+
+
+ /**
+ * Tells if the role is a TE SAP
+ */
+ private boolean isTriggerExecutionSpecificRole( String role )
+ {
+ return role.equalsIgnoreCase( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ) ||
+ role.equals( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
+ }
+
+
+ /**
+ * Tells if the role is a SS SAP
+ */
+ private boolean isSubschemaSpecficRole( String role )
+ {
+ return role.equalsIgnoreCase( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA ) ||
+ role.equals( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID );
+ }
+
+
+ /**
+ * Tells if the role is an AAP
+ */
+ private boolean isAutonomousAreaRole( String role )
+ {
+ return role.equalsIgnoreCase( SchemaConstants.AUTONOMOUS_AREA ) ||
+ role.equals( SchemaConstants.AUTONOMOUS_AREA_OID );
+ }
+
+
+ /**
+ * Tells if the Administrative Point role is an AAP
+ */
+ private boolean isAAP( Attribute adminPoint )
+ {
+ return ( adminPoint.contains( SchemaConstants.AUTONOMOUS_AREA ) || adminPoint
+ .contains( SchemaConstants.AUTONOMOUS_AREA_OID ) );
+ }
+
+
+ private boolean hasAccessControlSpecificRole( Attribute adminPoint )
+ {
+ return adminPoint.contains( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ) ||
+ adminPoint.contains( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
+ }
+
+
+ private boolean isIAP( String role )
+ {
+ return INNER_AREA_ROLES.contains( role );
+ }
+
+
+ private boolean hasCollectiveAttributeSpecificRole( Attribute adminPoint )
+ {
+ return adminPoint.contains( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ) ||
+ adminPoint.contains( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
+ }
+
+
+ private boolean hasTriggerExecutionSpecificRole( Attribute adminPoint )
+ {
+ return adminPoint.contains( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ) ||
+ adminPoint.contains( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
+ }
+
+
+ /**
+ * Check that we don't have an IAP and a SAP with the same family
+ */
+ private void checkInnerSpecificMix( String role, Attribute adminPoint ) throws LdapUnwillingToPerformException
+ {
+ if ( isAccessControlInnerRole( role ) )
+ {
+ if ( hasAccessControlSpecificRole( adminPoint ) )
+ {
+ // This is inconsistent
+ String message = "Cannot add a specific Administrative Point and the same"
+ + " inner Administrative point at the same time : " + adminPoint;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ if ( isCollectiveAttributeInnerRole( role ) )
+ {
+ if ( hasCollectiveAttributeSpecificRole( adminPoint ) )
+ {
+ // This is inconsistent
+ String message = "Cannot add a specific Administrative Point and the same"
+ + " inner Administrative point at the same time : " + adminPoint;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ if ( isTriggerExecutionInnerRole( role ) )
+ {
+ if ( hasTriggerExecutionSpecificRole( adminPoint ) )
+ {
+ // This is inconsistent
+ String message = "Cannot add a specific Administrative Point and the same"
+ + " inner Administrative point at the same time : " + adminPoint;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+
+ /**
+ * Check that the IAPs (if any) have a parent. We will check for each kind or role :
+ * AC, CA and TE.
+ */
+ private void checkIAPHasParent( String role, Attribute adminPoint, Dn dn )
+ throws LdapUnwillingToPerformException
+ {
+ // Check for the AC role
+ if ( isAccessControlInnerRole( role ) )
+ {
+ DnNode<AccessControlAdministrativePoint> acCache = directoryService.getAccessControlAPCache();
+
+ DnNode<AccessControlAdministrativePoint> parent = acCache.getNode( dn );
+
+ if ( parent == null )
+ {
+ // We don't have any AC administrativePoint in the tree, this is an error
+ String message = "Cannot add an IAP with no parent : " + adminPoint;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ }
+ else if ( isCollectiveAttributeInnerRole( role ) )
+ {
+ DnNode<CollectiveAttributeAdministrativePoint> caCache = directoryService.getCollectiveAttributeAPCache();
+
+ boolean hasAP = caCache.hasParentElement( dn );
+
+ if ( !hasAP )
+ {
+ // We don't have any AC administrativePoint in the tree, this is an error
+ String message = "Cannot add an IAP with no parent : " + adminPoint;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ }
+ else if ( isTriggerExecutionInnerRole( role ) )
+ {
+ DnNode<TriggerExecutionAdministrativePoint> caCache = directoryService.getTriggerExecutionAPCache();
+
+ DnNode<TriggerExecutionAdministrativePoint> parent = caCache.getNode( dn );
+
+ if ( parent == null )
+ {
+ // We don't have any AC administrativePoint in the tree, this is an error
+ String message = "Cannot add an IAP with no parent : " + adminPoint;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ }
+ else
+ {
+ // Wtf ? We *must* have an IAP here...
+ String message = "This is not an IAP : " + role;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ }
+
+
+ //-------------------------------------------------------------------------------------------
+ // Interceptor initialization
+ //-------------------------------------------------------------------------------------------
+ /**
+ * Registers and initializes all {@link Authenticator}s to this service.
+ */
+ public void init( DirectoryService directoryService ) throws LdapException
+ {
+ LOG.debug( "Initializing the AdministrativeInterceptor" );
+
+ super.init( directoryService );
+ nexus = directoryService.getPartitionNexus();
+
+ // Load all the AdministratvePoint :
+ // Autonomous Administrative Point first, then Specific
+ // administrative point, finally the Inner administrative Point
+ Dn adminDn = new Dn( schemaManager, ServerDNConstants.ADMIN_SYSTEM_DN );
+
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+ controls.setReturningAttributes( new String[]
+ { SchemaConstants.ADMINISTRATIVE_ROLE_AT } );
+
+ // get the list of all the AAPs
+ List<Entry> administrativePoints = getAdministrativePoints();
+
+ lockWrite();
+ addAdminPointCache( administrativePoints );
+ unlock();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void destroy()
+ {
+ }
+
+
+ private void updateAPEntries( Attribute adminPoint, String apUuid )
+ {
+ if ( isAAP( adminPoint ) )
+ {
+
+ }
+
+ return;
+ }
+
+
+ /**
+ * Add an administrative point into the DIT.
+ *
+ * We have to deal with some specific cases :
+ * <ul>
+ * <li>If it's an AA, then the added role should be the only one</li>
+ * <li>It's not possible to add IA and SA at the same time</li>
+ *
+ * @param next The next {@link Interceptor} in the chain
+ * @param addContext The {@link AddOperationContext} instance
+ * @throws LdapException If we had some error while processing the Add operation
+ */
+ public void add( NextInterceptor next, AddOperationContext addContext ) throws LdapException
+ {
+ LOG.debug( ">>> Entering into the Administrative Interceptor, addRequest" );
+ Entry entry = addContext.getEntry();
+ Dn dn = entry.getDn();
+
+ // Check if we are adding an Administrative Point
+ Attribute adminPoint = entry.get( ADMINISTRATIVE_ROLE_AT );
+
+ if ( adminPoint == null )
+ {
+ // Nope, go on.
+ next.add( addContext );
+
+ LOG.debug( "Exit from Administrative Interceptor, no AP in the added entry" );
+
+ return;
+ }
+
+ LOG.debug( "Addition of an administrative point at {} for the role {}", dn, adminPoint );
+
+ // Protect the AP caches against concurrent access
+ lockWrite();
+
+ // Loop on all the added roles to check if they are valid
+ for ( Value<?> role : adminPoint )
+ {
+ checkAddRole( role, adminPoint, dn );
+ }
+
+ // Ok, we are golden.
+ next.add( addContext );
+
+ String apUuid = entry.get( ENTRY_UUID_AT ).getString();
+
+ // Now, update the AdminPoint cache
+ createAdministrativePoints( adminPoint, dn, apUuid );
+
+ // Release the APCaches lock
+ unlock();
+
+ LOG.debug( "Added an Administrative Point at {}", dn );
+
+ return;
+ }
+
+
+ /**
+ * We have to check that we can remove the associated AdministrativePoint : <br/>
+ * <ul>
+ * <li> if we remove an AAP, no descendant IAP should remain orphan</li>
+ * <li> If we remove a SAP, no descendant IAP should remain orphan</li>
+ * </ul>
+ * {@inheritDoc}
+ */
+ public void delete( NextInterceptor next, DeleteOperationContext deleteContext ) throws LdapException
+ {
+ LOG.debug( ">>> Entering into the Administrative Interceptor, delRequest" );
+ Entry entry = deleteContext.getEntry();
+ Dn dn = entry.getDn();
+
+ // Check if we are deleting an Administrative Point
+ Attribute adminPoint = entry.get( ADMINISTRATIVE_ROLE_AT );
+
+ if ( adminPoint == null )
+ {
+ // Nope, go on.
+ next.delete( deleteContext );
+
+ LOG.debug( "Exit from Administrative Interceptor" );
+
+ return;
+ }
+
+ LOG.debug( "Deletion of an administrative point at {} for the role {}", dn, adminPoint );
+
+ // Protect the AP caches against concurrent access
+ lockWrite();
+
+ // Check that the removed AdministrativeRoles are valid. We don't have to do
+ // any other check, as the deleted entry has no children.
+ for ( Value<?> role : adminPoint )
+ {
+ if ( !isValidRole( role.getString() ) )
+ {
+ String message = "Cannot remove the given role, it's not a valid one :" + role;
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+ }
+
+ // Ok, we can remove the AP
+ next.delete( deleteContext );
+
+ // Now, update the AdminPoint cache
+ deleteAdminPointCache( adminPoint, deleteContext );
+
+ // Release the APCaches lock
+ unlock();
+
+ LOG.debug( "Deleted an Administrative Point at {}", dn );
+
+ return;
+ }
+
+
+ /**
+ * Only the add and remove modifications are fully supported. We have to check that the
+ * underlying APs are still consistent.
+ * We first have to compute the final AdministrativeRole, then do a diff with the
+ * initial attribute, to determinate which roles have been added and which ones have
+ * been deleted.
+ * Once this is done, we have to check that when deleting or adding each of those roles
+ * the admin model remains consistent.
+ *
+ * {@inheritDoc}
+ */
+ public void modify( NextInterceptor next, ModifyOperationContext modifyContext ) throws LdapException
+ {
+ LOG.debug( ">>> Entering into the Administrative Interceptor, modifyRequest" );
+ // We have to check that the modification is acceptable
+ List<Modification> modifications = modifyContext.getModItems();
+ Dn dn = modifyContext.getDn();
+ String uuid = modifyContext.getEntry().get( ENTRY_UUID_AT ).getString();
+
+ // Create a clone of the current AdminRole AT
+ Attribute modifiedAdminRole = ((ClonedServerEntry)modifyContext.getEntry() ).getOriginalEntry().get( ADMINISTRATIVE_ROLE_AT );
+
+ if ( modifiedAdminRole == null )
+ {
+ // Create the attribute
+ modifiedAdminRole = new DefaultAttribute( ADMINISTRATIVE_ROLE_AT );
+ }
+ else
+ {
+ modifiedAdminRole = modifiedAdminRole.clone();
+ }
+
+ // Clone the AP caches before applying modifications to them modify it
+ DnNode<AccessControlAdministrativePoint> acapCacheCopy = directoryService.getAccessControlAPCache().clone();
+ DnNode<CollectiveAttributeAdministrativePoint> caapCacheCopy = directoryService.getCollectiveAttributeAPCache().clone();
+ DnNode<TriggerExecutionAdministrativePoint> teapCacheCopy = directoryService.getTriggerExecutionAPCache().clone();
+ DnNode<SubschemaAdministrativePoint> ssapCacheCopy = directoryService.getSubschemaAPCache().clone();
+
+ // Loop on the modification to select the AdministrativeRole and process it :
+ // we will create a new AT containing all the roles after having applied the modifications
+ // on it
+ for ( Modification modification : modifications )
+ {
+ Attribute attribute = modification.getAttribute();
+
+ // Skip all the attributes but AdministrativeRole
+ if ( attribute.getAttributeType() == ADMINISTRATIVE_ROLE_AT )
+ {
+ // Ok, we have a modification impacting the administrative role
+ // Apply it to a virtual AdministrativeRole attribute
+ switch ( modification.getOperation() )
+ {
+ case ADD_ATTRIBUTE:
+ if ( modifiedAdminRole == null )
+ {
+ // Create the attribute
+ modifiedAdminRole = new DefaultAttribute( ADMINISTRATIVE_ROLE_AT, attribute.get() );
+ }
+
+ for ( Value<?> role : attribute )
+ {
+ addRole( role.getString(), dn, uuid, acapCacheCopy, caapCacheCopy, teapCacheCopy, ssapCacheCopy );
+
+ // Add the role to the modified attribute
+ modifiedAdminRole.add( role );
+ }
+
+ break;
+
+ case REMOVE_ATTRIBUTE:
+ if ( modifiedAdminRole == null )
+ {
+ // We can't remove a value when the attribute does not exist.
+ String msg = "Cannot remove the administrative role, it does not exist";
+ LOG.error( msg );
+ throw new LdapNoSuchAttributeException( msg );
+ }
+
+ // It may be a complete removal
+ if ( attribute.size() == 0 )
+ {
+ // Complete removal. Loop on all the existing roles and remove them
+ for ( Value<?> role : modifiedAdminRole )
+ {
+ //checkDelRole( role, modifiedAdminRole, dn, directoryService.getAdministrativePoints() );
+ delRole( role.getString(), dn, uuid, acapCacheCopy, caapCacheCopy, teapCacheCopy, ssapCacheCopy );
+ }
+
+ modifiedAdminRole.clear();
+ break;
+ }
+
+ // Now deal with the values to remove
+ for ( Value<?> value : attribute )
+ {
+ if ( !isValidRole( value.getString() ) )
+ {
+ // Not a valid role : we will throw an exception
+ String msg = "Invalid role : " + value.getString();
+ LOG.error( msg );
+ throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX,
+ msg );
+ }
+
+ if ( !modifiedAdminRole.contains( value ) )
+ {
+ // We can't remove a value if it does not exist !
+ String msg = "Cannot remove the administrative role value" + value
+ + ", it does not exist";
+ LOG.error( msg );
+ throw new LdapNoSuchAttributeException( msg );
+ }
+
+ modifiedAdminRole.remove( value );
+ delRole( value.getString(), dn, uuid, acapCacheCopy, caapCacheCopy, teapCacheCopy,
+ ssapCacheCopy );
+
+ }
+
+ break;
+
+ case REPLACE_ATTRIBUTE:
+ // Not supported
+ String msg = "Cannot replace an administrative role, the opertion is not supported";
+ LOG.error( msg );
+ throw new LdapUnwillingToPerformException( msg );
+ }
+ }
+ }
+
+ // At this point, we have a new AdministrativeRole AT, and we need to get the lists of
+ // added roles and removed roles, in order to process them
+
+ next.modify( modifyContext );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void move( NextInterceptor next, MoveOperationContext moveContext ) throws LdapException
+ {
+ LOG.debug( ">>> Entering into the Administrative Interceptor, moveRequest" );
+ Entry entry = moveContext.getOriginalEntry();
+
+ // Check if we are moving an Administrative Point
+ Attribute adminPoint = entry.get( ADMINISTRATIVE_ROLE_AT );
+
+ if ( adminPoint == null )
+ {
+ // Nope, go on.
+ next.move( moveContext );
+
+ LOG.debug( "Exit from Administrative Interceptor" );
+
+ return;
+ }
+
+ // Else throw an UnwillingToPerform exception ATM
+ String message = "Cannot move an Administrative Point in the current version";
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext moveAndRenameContext )
+ throws LdapException
+ {
+ LOG.debug( ">>> Entering into the Administrative Interceptor, moveAndRenameRequest" );
+ Entry entry = moveAndRenameContext.getOriginalEntry();
+
+ // Check if we are moving and renaming an Administrative Point
+ Attribute adminPoint = entry.get( ADMINISTRATIVE_ROLE_AT );
+
+ if ( adminPoint == null )
+ {
+ // Nope, go on.
+ next.moveAndRename( moveAndRenameContext );
+
+ LOG.debug( "Exit from Administrative Interceptor" );
+
+ return;
+ }
+
+ // Else throw an UnwillingToPerform exception ATM
+ String message = "Cannot move and rename an Administrative Point in the current version";
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void rename( NextInterceptor next, RenameOperationContext renameContext ) throws LdapException
+ {
+ LOG.debug( ">>> Entering into the Administrative Interceptor, renameRequest" );
+ Entry entry = renameContext.getEntry();
+
+ // Check if we are renaming an Administrative Point
+ Attribute adminPoint = entry.get( ADMINISTRATIVE_ROLE_AT );
+
+ if ( adminPoint == null )
+ {
+ // Nope, go on.
+ next.rename( renameContext );
+
+ LOG.debug( "Exit from Administrative Interceptor" );
+
+ return;
+ }
+
+ // Else throw an UnwillingToPerform exception ATM
+ String message = "Cannot rename an Administrative Point in the current version";
+ LOG.error( message );
+ throw new LdapUnwillingToPerformException( message );
+ }
+}
Propchange: directory/apacheds/branches/apacheds-txns/interceptors/authn/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Oct 20 19:41:49 2011
@@ -0,0 +1,5 @@
+bin
+target
+.classpath
+.project
+.settings
Added: directory/apacheds/branches/apacheds-txns/interceptors/authn/pom.xml
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/interceptors/authn/pom.xml?rev=1187013&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/interceptors/authn/pom.xml (added)
+++ directory/apacheds/branches/apacheds-txns/interceptors/authn/pom.xml Thu Oct 20 19:41:49 2011
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.directory.server</groupId>
+ <artifactId>apacheds-interceptors</artifactId>
+ <version>2.0.0-M4-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>apacheds-interceptors-authn</artifactId>
+ <name>ApacheDS Authentication Interceptor</name>
+ <packaging>bundle</packaging>
+
+ <description>
+ Authentication interceptor
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.directory.junit</groupId>
+ <artifactId>junit-addons</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>apacheds-i18n</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>apacheds-core-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>apacheds-core-api</artifactId>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>apacheds-core-shared</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-ldap-client-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-i18n</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-ldap-codec-standalone</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-ldap-codec-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-ldap-extras-aci</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-ldap-extras-trigger</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-ldap-extras-util</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-ldap-model</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-ldap-schema-data</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-util</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>bouncycastle</groupId>
+ <artifactId>bcprov-jdk15</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>net.sf.ehcache</groupId>
+ <artifactId>ehcache-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.directory.shared</groupId>
+ <artifactId>shared-ldap-extras-codec</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <workingDirectory>${basedir}/target/server-work</workingDirectory>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+ <addMavenDescriptor>false</addMavenDescriptor>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <inherited>true</inherited>
+ <extensions>true</extensions>
+ <configuration>
+ <manifestLocation>META-INF</manifestLocation>
+ <instructions>
+ <Bundle-SymbolicName>${project.groupId}.interceptors.authn</Bundle-SymbolicName>
+ <Export-Package>
+ {local-packages};version=${project.version};-noimport:=true
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ <excludes>
+ <exclude>**/*.gif</exclude>
+ </excludes>
+ </resource>
+ </resources>
+ </build>
+</project>
+
Added: directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AbstractAuthenticator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AbstractAuthenticator.java?rev=1187013&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AbstractAuthenticator.java (added)
+++ directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AbstractAuthenticator.java Thu Oct 20 19:41:49 2011
@@ -0,0 +1,260 @@
+/*
+ * 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.authn;
+
+
+import static org.apache.directory.shared.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum.ACCOUNT_LOCKED;
+import static org.apache.directory.shared.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum.PASSWORD_EXPIRED;
+import static org.apache.directory.shared.ldap.model.constants.PasswordPolicySchemaConstants.PWD_ACCOUNT_LOCKED_TIME_AT;
+import static org.apache.directory.shared.ldap.model.constants.PasswordPolicySchemaConstants.PWD_CHANGED_TIME_AT;
+import static org.apache.directory.shared.ldap.model.constants.PasswordPolicySchemaConstants.PWD_END_TIME_AT;
+import static org.apache.directory.shared.ldap.model.constants.PasswordPolicySchemaConstants.PWD_GRACE_USE_TIME_AT;
+import static org.apache.directory.shared.ldap.model.constants.PasswordPolicySchemaConstants.PWD_LAST_SUCCESS_AT;
+import static org.apache.directory.shared.ldap.model.constants.PasswordPolicySchemaConstants.PWD_START_TIME_AT;
+
+import java.util.Date;
+
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyConfiguration;
+import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyException;
+import org.apache.directory.shared.ldap.model.constants.AuthenticationLevel;
+import org.apache.directory.shared.ldap.model.entry.Attribute;
+import org.apache.directory.shared.ldap.model.entry.DefaultModification;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.Modification;
+import org.apache.directory.shared.ldap.model.entry.ModificationOperation;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.util.DateUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for all Authenticators.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractAuthenticator implements Authenticator
+{
+ /** A logger for the extending classes */
+ protected static final Logger LOG = LoggerFactory.getLogger( AbstractAuthenticator.class );
+
+ /** The associated DirectoryService */
+ private DirectoryService directoryService;
+
+ /** authenticator type */
+ private final AuthenticationLevel authenticatorType;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param type the type of this authenticator (e.g. <tt>'simple'</tt>, <tt>'none'</tt>...)
+ */
+ protected AbstractAuthenticator( AuthenticationLevel type )
+ {
+ this.authenticatorType = type;
+ }
+
+
+ /**
+ * Returns {@link DirectoryService} for this authenticator.
+ * @return the directory service core
+ */
+ public DirectoryService getDirectoryService()
+ {
+ return directoryService;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public AuthenticationLevel getAuthenticatorType()
+ {
+ return authenticatorType;
+ }
+
+
+ /**
+ * Initializes (<tt>directoryService</tt> and and calls {@link #doInit()} method.
+ * Please put your initialization code into {@link #doInit()}.
+ * @param directoryService the directory core for this authenticator
+ * @throws LdapException if there is a problem starting up the authenticator
+ */
+ public final void init( DirectoryService directoryService ) throws LdapException
+ {
+ this.directoryService = directoryService;
+ doInit();
+ }
+
+
+ /**
+ * Implement your initialization code here.
+ */
+ protected void doInit()
+ {
+ }
+
+
+ /**
+ * Calls {@link #doDestroy()} method, and clears default properties
+ * (<tt>factoryConfiguration</tt> and <tt>configuration</tt>).
+ * Please put your deinitialization code into {@link #doDestroy()}.
+ */
+ public final void destroy()
+ {
+ try
+ {
+ doDestroy();
+ }
+ finally
+ {
+ this.directoryService = null;
+ }
+ }
+
+
+ /**
+ * Implement your deinitialization code here.
+ */
+ protected void doDestroy()
+ {
+ }
+
+
+ /**
+ * Does nothing leaving it so subclasses can override.
+ */
+ public void invalidateCache( Dn bindDn )
+ {
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void checkPwdPolicy( Entry userEntry ) throws LdapException
+ {
+ if( !directoryService.isPwdPolicyEnabled() )
+ {
+ return;
+ }
+
+ AuthenticationInterceptor authenticationInterceptor = (AuthenticationInterceptor)directoryService.getInterceptor( AuthenticationInterceptor.class.getSimpleName() );
+ PasswordPolicyConfiguration pPolicyConfig = authenticationInterceptor.getPwdPolicy( userEntry );
+
+ // check for locked out account
+ if( pPolicyConfig.isPwdLockout() )
+ {
+ LOG.debug( "checking if account with the Dn {} is locked", userEntry.getDn() );
+
+ Attribute accountLockAttr = userEntry.get( PWD_ACCOUNT_LOCKED_TIME_AT );
+ if( accountLockAttr != null )
+ {
+ String lockedTime = accountLockAttr.getString();
+ if( lockedTime.equals( "000001010000Z" ) )
+ {
+ throw new PasswordPolicyException( "account was permanently locked", ACCOUNT_LOCKED.getValue() );
+ }
+ else
+ {
+ Date lockedDate = DateUtils.getDate( lockedTime );
+ long time = pPolicyConfig.getPwdLockoutDuration() * 1000;
+ time += lockedDate.getTime();
+
+ Date unlockedDate = new Date( time );
+ if( lockedDate.before( unlockedDate ) )
+ {
+ throw new PasswordPolicyException( "account will remain locked till " + unlockedDate, ACCOUNT_LOCKED.getValue() );
+ }
+ else
+ {
+ // remove pwdAccountLockedTime attribute
+ Modification pwdAccountLockMod = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, accountLockAttr );
+
+ // DO NOT bypass the interceptor chain, otherwise the changes can't be replicated
+ directoryService.getAdminSession().modify( userEntry.getDn(), pwdAccountLockMod );
+ }
+ }
+ }
+ }
+
+ Attribute pwdStartTimeAttr = userEntry.get( PWD_START_TIME_AT );
+ if( pwdStartTimeAttr != null )
+ {
+ Date pwdStartTime = DateUtils.getDate( pwdStartTimeAttr.getString() );
+
+ if( System.currentTimeMillis() < pwdStartTime.getTime() )
+ {
+ throw new PasswordPolicyException( "account is locked, will be activated after " + pwdStartTime, ACCOUNT_LOCKED.getValue() );
+ }
+ }
+
+ Attribute pwdEndTimeAttr = userEntry.get( PWD_END_TIME_AT );
+ if( pwdEndTimeAttr != null )
+ {
+ Date pwdEndTime = DateUtils.getDate( pwdEndTimeAttr.getString() );
+
+ if( System.currentTimeMillis() >= pwdEndTime.getTime() )
+ {
+ throw new PasswordPolicyException( "password end time reached, will be locked till administrator activates it", ACCOUNT_LOCKED.getValue() );
+ }
+ }
+
+ if( pPolicyConfig.getPwdMaxIdle() > 0 )
+ {
+ Attribute pwdLastSuccessTimeAttr = userEntry.get( PWD_LAST_SUCCESS_AT );
+ long time = pPolicyConfig.getPwdMaxIdle() * 1000;
+ time += DateUtils.getDate( pwdLastSuccessTimeAttr.getString() ).getTime();
+
+ if( System.currentTimeMillis() >= time )
+ {
+ throw new PasswordPolicyException( "account locked due to the max idle time of the password was exceeded", ACCOUNT_LOCKED.getValue() );
+ }
+ }
+
+ if ( pPolicyConfig.getPwdMaxAge() > 0 )
+ {
+ if( pPolicyConfig.getPwdGraceAuthNLimit() > 0 )
+ {
+ Attribute pwdGraceUseAttr = userEntry.get( PWD_GRACE_USE_TIME_AT );
+
+ // check for grace authentication count
+ if( pwdGraceUseAttr != null )
+ {
+ if( pwdGraceUseAttr.size() >= pPolicyConfig.getPwdGraceAuthNLimit() )
+ {
+ throw new PasswordPolicyException( "paasword expired and max grace logins were used", PASSWORD_EXPIRED.getValue() );
+ }
+ }
+ }
+ else
+ {
+ Attribute pwdChangeTimeAttr = userEntry.get( PWD_CHANGED_TIME_AT );
+ boolean expired = PasswordUtil.isPwdExpired( pwdChangeTimeAttr.getString(), pPolicyConfig.getPwdMaxAge() );
+
+ if( expired )
+ {
+ throw new PasswordPolicyException( "paasword expired", PASSWORD_EXPIRED.getValue() );
+ }
+ }
+ }
+ }
+}
Added: directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AnonymousAuthenticator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AnonymousAuthenticator.java?rev=1187013&view=auto
==============================================================================
--- directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AnonymousAuthenticator.java (added)
+++ directory/apacheds/branches/apacheds-txns/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AnonymousAuthenticator.java Thu Oct 20 19:41:49 2011
@@ -0,0 +1,79 @@
+/*
+ * 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.authn;
+
+
+import java.net.SocketAddress;
+
+import org.apache.directory.server.core.api.LdapPrincipal;
+import org.apache.directory.server.core.api.interceptor.context.BindOperationContext;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.shared.ldap.model.constants.AuthenticationLevel;
+import org.apache.directory.shared.ldap.model.exception.LdapNoPermissionException;
+import org.apache.mina.core.session.IoSession;
+
+
+/**
+ * An {@link Authenticator} that handles anonymous connections
+ * (type <tt>'none'</tt>).
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AnonymousAuthenticator extends AbstractAuthenticator
+{
+ /**
+ * Creates a new instance.
+ */
+ public AnonymousAuthenticator()
+ {
+ super( AuthenticationLevel.NONE );
+ }
+
+
+ /**
+ * If the context is not configured to allow anonymous connections,
+ * this method throws a {@link javax.naming.NoPermissionException}.
+ */
+ public LdapPrincipal authenticate( BindOperationContext bindContext ) throws LdapNoPermissionException
+ {
+ // We only allow Anonymous binds if the service allows them
+ if ( getDirectoryService().isAllowAnonymousAccess() )
+ {
+ LdapPrincipal principal = getDirectoryService().getAdminSession().getAnonymousPrincipal();
+
+ IoSession session = bindContext.getIoSession();
+
+ if ( session != null )
+ {
+ SocketAddress clientAddress = session.getRemoteAddress();
+ principal.setClientAddress( clientAddress );
+ SocketAddress serverAddress = session.getServiceAddress();
+ principal.setServerAddress( serverAddress );
+ }
+
+ return principal;
+ }
+ else
+ {
+ LOG.info( "Cannot authenticate as anonymous, the server does not allow it" );
+ throw new LdapNoPermissionException( I18n.err( I18n.ERR_228 ) );
+ }
+ }
+}