You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ka...@apache.org on 2015/01/25 15:18:46 UTC

svn commit: r1654657 - in /directory/apacheds/trunk: interceptors/authn/src/main/java/org/apache/directory/server/core/authn/ interceptors/authn/src/main/java/org/apache/directory/server/core/authn/ppolicy/ server-config/src/main/java/org/apache/direct...

Author: kayyagari
Date: Sun Jan 25 14:18:45 2015
New Revision: 1654657

URL: http://svn.apache.org/r1654657
Log:
o support for applying password policy config changes dynamically (DIRSERVER-1809)
o updated the ppolicy config container to support dynamic configuration
o updated authentication interceptor to return default policy when the user is anonymour or the custom policy is missing
o refactored ConfigPartitionReader to avoid searching when an entry is already available
o updated tests

Added:
    directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/listener/
    directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/listener/ConfigChangeListener.java
Modified:
    directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java
    directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/ppolicy/PpolicyConfigContainer.java
    directory/apacheds/trunk/server-config/src/main/java/org/apache/directory/server/config/ConfigPartitionReader.java
    directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/extended/PwdModifyIT.java
    directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ppolicy/PasswordPolicyIT.java
    directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/builder/ServiceBuilder.java
    directory/apacheds/trunk/service/src/main/java/org/apache/directory/server/ApacheDsService.java

Modified: directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java?rev=1654657&r1=1654656&r2=1654657&view=diff
==============================================================================
--- directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java (original)
+++ directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java Sun Jan 25 14:18:45 2015
@@ -1623,6 +1623,11 @@ public class AuthenticationInterceptor e
             return null;
         }
 
+        if ( userEntry == null )
+        {
+            return pwdPolicyContainer.getDefaultPolicy();
+        }
+        
         if ( pwdPolicyContainer.hasCustomConfigs() )
         {
             Attribute pwdPolicySubentry = userEntry.get( pwdPolicySubentryAT );
@@ -1631,7 +1636,15 @@ public class AuthenticationInterceptor e
             {
                 Dn configDn = dnFactory.create( pwdPolicySubentry.getString() );
 
-                return pwdPolicyContainer.getPolicyConfig( configDn );
+                PasswordPolicyConfiguration custom = pwdPolicyContainer.getPolicyConfig( configDn );
+                if ( custom != null )
+                {
+                    return custom;
+                }
+                else
+                {
+                    LOG.warn( "The custom password policy for the user entry {} is not found, returning default policy configuration", userEntry.getDn() );
+                }
             }
         }
 

Modified: directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/ppolicy/PpolicyConfigContainer.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/ppolicy/PpolicyConfigContainer.java?rev=1654657&r1=1654656&r2=1654657&view=diff
==============================================================================
--- directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/ppolicy/PpolicyConfigContainer.java (original)
+++ directory/apacheds/trunk/interceptors/authn/src/main/java/org/apache/directory/server/core/authn/ppolicy/PpolicyConfigContainer.java Sun Jan 25 14:18:45 2015
@@ -39,8 +39,8 @@ public class PpolicyConfigContainer
     /** a map holding the entry specific password policies */
     private Map<Dn, PasswordPolicyConfiguration> ppolicyConfigMap = new HashMap<Dn, PasswordPolicyConfiguration>();
 
-    /** the default password policy */
-    private PasswordPolicyConfiguration defaultPolicy;
+    /** the default password policy Dn */
+    private Dn defaultPolicyDn;
 
 
     /**
@@ -86,18 +86,18 @@ public class PpolicyConfigContainer
      */
     public PasswordPolicyConfiguration getDefaultPolicy()
     {
-        return defaultPolicy;
+        return getPolicyConfig( defaultPolicyDn );
     }
 
 
     /**
-     * Set the default password policy configuration
+     * Set the default password policy configuration's Dn
      * 
-     * @param defaultPolicy the password policy configuration instance
+     * @param defaultPolicyDn the default password policy configuration's Dn 
      */
-    public void setDefaultPolicy( PasswordPolicyConfiguration defaultPolicy )
+    public void setDefaultPolicyDn( Dn defaultPolicyDn )
     {
-        this.defaultPolicy = defaultPolicy;
+        this.defaultPolicyDn = defaultPolicyDn;
     }
 
 

Modified: directory/apacheds/trunk/server-config/src/main/java/org/apache/directory/server/config/ConfigPartitionReader.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-config/src/main/java/org/apache/directory/server/config/ConfigPartitionReader.java?rev=1654657&r1=1654656&r2=1654657&view=diff
==============================================================================
--- directory/apacheds/trunk/server-config/src/main/java/org/apache/directory/server/config/ConfigPartitionReader.java (original)
+++ directory/apacheds/trunk/server-config/src/main/java/org/apache/directory/server/config/ConfigPartitionReader.java Sun Jan 25 14:18:45 2015
@@ -478,7 +478,7 @@ public class ConfigPartitionReader
     /**
      * Read some configuration element from the DIT using its name
      */
-    private List<AdsBaseBean> read( Dn baseDn, String name, SearchScope scope, boolean mandatory )
+    public List<AdsBaseBean> read( Dn baseDn, String name, SearchScope scope, boolean mandatory )
         throws ConfigurationException
     {
         LOG.debug( "Reading from '{}', objectClass '{}'", baseDn, name );
@@ -532,100 +532,9 @@ public class ConfigPartitionReader
                 Entry entry = configPartition.fetch( forwardEntry.getId() );
                 LOG.debug( "Entry read : {}", entry );
 
-                // Let's instantiate the bean we need. The upper ObjectClass's name
-                // will be used to do that
-                ObjectClass objectClass = findObjectClass( entry.get( SchemaConstants.OBJECT_CLASS_AT ) );
-
-                // Instantiating the bean
-                AdsBaseBean bean = createBean( objectClass );
-
-                // Setting its DN
-                bean.setDn( entry.getDn() );
-
+                AdsBaseBean bean = readConfig( entry );
                 // Adding the bean to the list
                 beansList.add( bean );
-
-                // Getting the class of the bean
-                Class<?> beanClass = bean.getClass();
-
-                // A flag to know when we reached the 'AdsBaseBean' class when 
-                // looping on the class hierarchy of the bean
-                boolean adsBaseBeanClassFound = false;
-
-                // Looping until the 'AdsBaseBean' class has been found
-                while ( !adsBaseBeanClassFound )
-                {
-                    // Checking if we reached the 'AdsBaseBean' class
-                    if ( beanClass == AdsBaseBean.class )
-                    {
-                        adsBaseBeanClassFound = true;
-                    }
-
-                    // Looping on all fields of the bean
-                    Field[] fields = beanClass.getDeclaredFields();
-                    for ( Field field : fields )
-                    {
-                        // Making the field accessible (we get an exception if we don't do that)
-                        field.setAccessible( true );
-
-                        // Getting the class of the field
-                        Class<?> fieldClass = field.getType();
-
-                        // Looking for the @ConfigurationElement annotation
-                        ConfigurationElement configurationElement = field.getAnnotation( ConfigurationElement.class );
-                        if ( configurationElement != null )
-                        {
-                            // Getting the annotation's values
-                            String fieldAttributeType = configurationElement.attributeType();
-                            String fieldObjectClass = configurationElement.objectClass();
-                            String container = configurationElement.container();
-                            boolean isOptional = configurationElement.isOptional();
-
-                            // Checking if we have a value for the attribute type
-                            if ( ( fieldAttributeType != null ) && ( !"".equals( fieldAttributeType ) ) )
-                            {
-                                readFieldValue( bean, field, entry, fieldAttributeType, !isOptional );
-                            }
-                            // Checking if we have a value for the object class
-                            else if ( ( fieldObjectClass != null ) && ( !"".equals( fieldObjectClass ) ) )
-                            {
-                                // Checking if this is a multi-valued field (which values are stored in a container)
-                                if ( isMultiple( fieldClass ) && ( container != null )
-                                    && ( !"".equals( container ) ) )
-                                {
-                                    // Creating the DN of the container
-                                    Dn newBase = entry.getDn().add( "ou=" + container );
-
-                                    // Looking for the field values
-                                    Collection<AdsBaseBean> fieldValues = read( newBase, fieldObjectClass,
-                                        SearchScope.ONELEVEL, !isOptional );
-
-                                    // Setting the values to the field
-                                    if ( ( fieldValues != null ) && ( fieldValues.size() > 0 ) )
-                                    {
-                                        field.set( bean, fieldValues );
-                                    }
-                                }
-                                // This is a single-value field
-                                else
-                                {
-                                    // Looking for the field values
-                                    List<AdsBaseBean> fieldValues = read( entry.getDn(), fieldObjectClass,
-                                        SearchScope.ONELEVEL, !isOptional );
-
-                                    // Setting the value to the field
-                                    if ( ( fieldValues != null ) && ( fieldValues.size() > 0 ) )
-                                    {
-                                        field.set( bean, fieldValues.get( 0 ) );
-                                    }
-                                }
-                            }
-                        }
-                    }
-
-                    // Moving to the upper class in the class hierarchy
-                    beanClass = beanClass.getSuperclass();
-                }
             }
             while ( cursor.next() );
         }
@@ -662,6 +571,111 @@ public class ConfigPartitionReader
 
 
     /**
+     * Creates a configuration bean from the given entry.
+     * 
+     * @param entry any configuration entry of thetype "ads-base"
+     * @return
+     * @throws Exception
+     */
+    public AdsBaseBean readConfig( Entry entry ) throws Exception
+    {
+        // Let's instantiate the bean we need. The upper ObjectClass's name
+        // will be used to do that
+        ObjectClass objectClass = findObjectClass( entry.get( SchemaConstants.OBJECT_CLASS_AT ) );
+
+        // Instantiating the bean
+        AdsBaseBean bean = createBean( objectClass );
+
+        // Setting its DN
+        bean.setDn( entry.getDn() );
+
+        // Getting the class of the bean
+        Class<?> beanClass = bean.getClass();
+
+        // A flag to know when we reached the 'AdsBaseBean' class when 
+        // looping on the class hierarchy of the bean
+        boolean adsBaseBeanClassFound = false;
+
+        // Looping until the 'AdsBaseBean' class has been found
+        while ( !adsBaseBeanClassFound )
+        {
+            // Checking if we reached the 'AdsBaseBean' class
+            if ( beanClass == AdsBaseBean.class )
+            {
+                adsBaseBeanClassFound = true;
+            }
+
+            // Looping on all fields of the bean
+            Field[] fields = beanClass.getDeclaredFields();
+            for ( Field field : fields )
+            {
+                // Making the field accessible (we get an exception if we don't do that)
+                field.setAccessible( true );
+
+                // Getting the class of the field
+                Class<?> fieldClass = field.getType();
+
+                // Looking for the @ConfigurationElement annotation
+                ConfigurationElement configurationElement = field.getAnnotation( ConfigurationElement.class );
+                if ( configurationElement != null )
+                {
+                    // Getting the annotation's values
+                    String fieldAttributeType = configurationElement.attributeType();
+                    String fieldObjectClass = configurationElement.objectClass();
+                    String container = configurationElement.container();
+                    boolean isOptional = configurationElement.isOptional();
+
+                    // Checking if we have a value for the attribute type
+                    if ( ( fieldAttributeType != null ) && ( !"".equals( fieldAttributeType ) ) )
+                    {
+                        readFieldValue( bean, field, entry, fieldAttributeType, !isOptional );
+                    }
+                    // Checking if we have a value for the object class
+                    else if ( ( fieldObjectClass != null ) && ( !"".equals( fieldObjectClass ) ) )
+                    {
+                        // Checking if this is a multi-valued field (which values are stored in a container)
+                        if ( isMultiple( fieldClass ) && ( container != null )
+                            && ( !"".equals( container ) ) )
+                        {
+                            // Creating the DN of the container
+                            Dn newBase = entry.getDn().add( "ou=" + container );
+
+                            // Looking for the field values
+                            Collection<AdsBaseBean> fieldValues = read( newBase, fieldObjectClass,
+                                SearchScope.ONELEVEL, !isOptional );
+
+                            // Setting the values to the field
+                            if ( ( fieldValues != null ) && ( fieldValues.size() > 0 ) )
+                            {
+                                field.set( bean, fieldValues );
+                            }
+                        }
+                        // This is a single-value field
+                        else
+                        {
+                            // Looking for the field values
+                            List<AdsBaseBean> fieldValues = read( entry.getDn(), fieldObjectClass,
+                                SearchScope.ONELEVEL, !isOptional );
+
+                            // Setting the value to the field
+                            if ( ( fieldValues != null ) && ( fieldValues.size() > 0 ) )
+                            {
+                                field.set( bean, fieldValues.get( 0 ) );
+                            }
+                        }
+                    }
+                }
+            }
+
+            // Moving to the upper class in the class hierarchy
+            beanClass = beanClass.getSuperclass();
+        }
+        
+        return bean;
+    }
+    
+    
+    /**
      * Indicates the given type is multiple.
      *
      * @param clazz

Modified: directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/extended/PwdModifyIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/extended/PwdModifyIT.java?rev=1654657&r1=1654656&r2=1654657&view=diff
==============================================================================
--- directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/extended/PwdModifyIT.java (original)
+++ directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/extended/PwdModifyIT.java Sun Jan 25 14:18:45 2015
@@ -196,7 +196,10 @@ public class PwdModifyIT extends Abstrac
         policyConfig.setPwdCheckQuality( CheckQualityEnum.CHECK_REJECT ); // DO NOT allow the password if its quality can't be checked
 
         PpolicyConfigContainer policyContainer = new PpolicyConfigContainer();
-        policyContainer.setDefaultPolicy( policyConfig );
+        Dn defaultPolicyDn = new Dn( ldapServer.getDirectoryService().getSchemaManager(), "cn=default" );
+        policyContainer.addPolicy( defaultPolicyDn, policyConfig );
+        policyContainer.setDefaultPolicyDn( defaultPolicyDn );
+        
         AuthenticationInterceptor authenticationInterceptor = ( AuthenticationInterceptor ) getService()
             .getInterceptor( InterceptorEnum.AUTHENTICATION_INTERCEPTOR.getName() );
 

Modified: directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ppolicy/PasswordPolicyIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ppolicy/PasswordPolicyIT.java?rev=1654657&r1=1654656&r2=1654657&view=diff
==============================================================================
--- directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ppolicy/PasswordPolicyIT.java (original)
+++ directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ppolicy/PasswordPolicyIT.java Sun Jan 25 14:18:45 2015
@@ -113,6 +113,7 @@ public class PasswordPolicyIT extends Ab
 
     private PasswordPolicyConfiguration policyConfig;
 
+    private Dn customPolicyDn;
 
     /**
      * Set a default PaswordPolicy configuration
@@ -134,7 +135,13 @@ public class PasswordPolicyIT extends Ab
         policyConfig.setPwdCheckQuality( CheckQualityEnum.CHECK_REJECT ); // DO NOT allow the password if its quality can't be checked
 
         PpolicyConfigContainer policyContainer = new PpolicyConfigContainer();
-        policyContainer.setDefaultPolicy( policyConfig );
+        Dn defaultPolicyDn = new Dn( ldapServer.getDirectoryService().getSchemaManager(), "cn=default" );
+        policyContainer.addPolicy( defaultPolicyDn, policyConfig );
+        policyContainer.setDefaultPolicyDn( defaultPolicyDn );
+
+        customPolicyDn = new Dn( ldapServer.getDirectoryService().getSchemaManager(), "cn=custom" );
+        policyContainer.addPolicy( customPolicyDn, policyConfig );
+
         AuthenticationInterceptor authenticationInterceptor = ( AuthenticationInterceptor ) getService()
             .getInterceptor( InterceptorEnum.AUTHENTICATION_INTERCEPTOR.getName() );
 
@@ -869,7 +876,7 @@ public class PasswordPolicyIT extends Ab
             "cn: ppolicySubentry",
             "sn: ppolicySubentry_sn",
             "userPassword: " + password,
-            "pwdPolicySubEntry:" + userDn.getName() );
+            "pwdPolicySubEntry:" + customPolicyDn.getName() );
 
         AddRequest addRequest = new AddRequestImpl();
         addRequest.setEntry( userEntry );
@@ -879,7 +886,7 @@ public class PasswordPolicyIT extends Ab
         assertEquals( ResultCodeEnum.SUCCESS, addResp.getLdapResult().getResultCode() );
 
         userEntry = adminConnection.lookup( userDn, "*", "+" );
-        assertEquals( userDn.getName(), userEntry.get( "pwdPolicySubEntry" ).getString() );
+        assertEquals( customPolicyDn.getName(), userEntry.get( "pwdPolicySubEntry" ).getString() );
 
         ModifyRequest modReq = new ModifyRequestImpl();
         modReq.setName( userDn );

Modified: directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/builder/ServiceBuilder.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/builder/ServiceBuilder.java?rev=1654657&r1=1654656&r2=1654657&view=diff
==============================================================================
--- directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/builder/ServiceBuilder.java (original)
+++ directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/builder/ServiceBuilder.java Sun Jan 25 14:18:45 2015
@@ -202,14 +202,12 @@ public class ServiceBuilder
 
                         if ( ppolicyConfig != null )
                         {
+                            ppolicyContainer.addPolicy( ppolicyBean.getDn(), ppolicyConfig );
+
                             // the name should be strictly 'default', the default policy can't be enforced by defining a new AT
                             if ( ppolicyBean.getPwdId().equalsIgnoreCase( "default" ) )
                             {
-                                ppolicyContainer.setDefaultPolicy( ppolicyConfig );
-                            }
-                            else
-                            {
-                                ppolicyContainer.addPolicy( ppolicyBean.getDn(), ppolicyConfig );
+                                ppolicyContainer.setDefaultPolicyDn( ppolicyBean.getDn() );
                             }
                         }
                     }

Added: directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/listener/ConfigChangeListener.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/listener/ConfigChangeListener.java?rev=1654657&view=auto
==============================================================================
--- directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/listener/ConfigChangeListener.java (added)
+++ directory/apacheds/trunk/service-builder/src/main/java/org/apache/directory/server/config/listener/ConfigChangeListener.java Sun Jan 25 14:18:45 2015
@@ -0,0 +1,195 @@
+/*
+ *   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.config.listener;
+
+
+import static org.apache.directory.server.core.api.InterceptorEnum.AUTHENTICATION_INTERCEPTOR;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+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.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.server.config.ConfigPartitionReader;
+import org.apache.directory.server.config.beans.PasswordPolicyBean;
+import org.apache.directory.server.config.builder.ServiceBuilder;
+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.event.DirectoryListenerAdapter;
+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.authn.AuthenticationInterceptor;
+import org.apache.directory.server.core.authn.ppolicy.PpolicyConfigContainer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A listener for handling the config partition changes.
+ * 
+ * Note: currently handles password policy related configuration changes only.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ConfigChangeListener extends DirectoryListenerAdapter
+{
+    /** the config parition reader */
+    private ConfigPartitionReader cpReader;
+
+    /** the directory service */
+    private DirectoryService directoryService;
+
+    /** container holding the current active password policy configurations */
+    private PpolicyConfigContainer ppolicyConfigContainer;
+
+    /** the root DN of password policy configurations */
+    private Dn ppolicyConfigDnRoot;
+
+    private static final String PPOLICY_OC_NAME = "ads-passwordPolicy";
+
+    // attribute holding the value of #PPOLICY_OC_NAME
+    private Attribute AT_PWDPOLICY;
+    
+    
+    /** The logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ConfigChangeListener.class );
+
+    /**
+     * 
+     * Creates a new instance of ConfigChangeListener.
+     *
+     * @param cpReader the configuration reader
+     * @param directoryService the DirectoryService instance
+     * @throws LdapException
+     */
+    public ConfigChangeListener( ConfigPartitionReader cpReader, DirectoryService directoryService )
+        throws LdapException
+    {
+        this.cpReader = cpReader;
+        this.directoryService = directoryService;
+
+        SchemaManager schemaManager = directoryService.getSchemaManager();
+
+        ppolicyConfigDnRoot = new Dn(
+            "ou=passwordPolicies,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config" );
+        ppolicyConfigDnRoot.apply( schemaManager );
+
+        AuthenticationInterceptor authInterceptor = ( AuthenticationInterceptor ) directoryService
+            .getInterceptor( AUTHENTICATION_INTERCEPTOR.getName() );
+        ppolicyConfigContainer = authInterceptor.getPwdPolicyContainer();
+
+        AttributeType ocType = schemaManager.lookupAttributeTypeRegistry( SchemaConstants.OBJECT_CLASS_AT );
+        AT_PWDPOLICY = new DefaultAttribute( ocType, PPOLICY_OC_NAME );
+    }
+
+
+    @Override
+    public void entryAdded( AddOperationContext addContext )
+    {
+        Entry entry = addContext.getEntry();
+        updatePasswordPolicy( entry, false );
+    }
+
+
+    @Override
+    public void entryDeleted( DeleteOperationContext deleteContext )
+    {
+        Entry entry = deleteContext.getEntry();
+        updatePasswordPolicy( entry, true );
+    }
+
+
+    @Override
+    public void entryModified( ModifyOperationContext modifyContext )
+    {
+        Entry entry = modifyContext.getAlteredEntry();
+        updatePasswordPolicy( entry, false );
+    }
+
+
+    /**
+     * Updates the password policy represented by the given configuration entry
+     * 
+     * @param entry the password policy configuration entry
+     * @param deleted flag to detect if this is a deleted entry
+     */
+    private void updatePasswordPolicy( Entry entry, boolean deleted )
+    {
+        Dn dn = entry.getDn();
+
+        if ( !dn.isDescendantOf( ppolicyConfigDnRoot ) )
+        {
+            return;
+        }
+
+        if ( !entry.contains( AT_PWDPOLICY ) )
+        {
+            return;
+        }
+
+        if ( deleted )
+        {
+            LOG.debug( "Deleting ppolicy config {}", dn );
+            ppolicyConfigContainer.removePolicyConfig( dn );
+            return;
+        }
+        
+        PasswordPolicyBean bean = null;
+        
+        try
+        {
+            bean = ( PasswordPolicyBean ) cpReader.readConfig( entry );
+        }
+        catch( Exception e )
+        {
+            LOG.warn( "Failed to read the updated ppolicy configuration from {}", dn );
+            LOG.warn("", e);
+            return;
+        }
+
+        if( bean.isDisabled() )
+        {
+            LOG.debug( "Deleting disabled ppolicy config {}", dn );
+            ppolicyConfigContainer.removePolicyConfig( dn );
+        }
+        else
+        {
+            PasswordPolicyConfiguration updated = ServiceBuilder.createPwdPolicyConfig( bean );
+            
+            PasswordPolicyConfiguration existing = ppolicyConfigContainer.getPolicyConfig( dn );
+            
+            if( existing == null )
+            {
+                LOG.debug( "Adding ppolicy config {}", dn );
+            }
+            else
+            {
+                LOG.debug( "Updating ppolicy config {}", dn );
+            }
+            
+            ppolicyConfigContainer.addPolicy( dn, updated );
+        }
+    }
+}

Modified: directory/apacheds/trunk/service/src/main/java/org/apache/directory/server/ApacheDsService.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/service/src/main/java/org/apache/directory/server/ApacheDsService.java?rev=1654657&r1=1654656&r2=1654657&view=diff
==============================================================================
--- directory/apacheds/trunk/service/src/main/java/org/apache/directory/server/ApacheDsService.java (original)
+++ directory/apacheds/trunk/service/src/main/java/org/apache/directory/server/ApacheDsService.java Sun Jan 25 14:18:45 2015
@@ -62,11 +62,14 @@ import org.apache.directory.server.confi
 import org.apache.directory.server.config.beans.LdapServerBean;
 import org.apache.directory.server.config.beans.NtpServerBean;
 import org.apache.directory.server.config.builder.ServiceBuilder;
+import org.apache.directory.server.config.listener.ConfigChangeListener;
 import org.apache.directory.server.core.api.CacheService;
 import org.apache.directory.server.core.api.CoreSession;
 import org.apache.directory.server.core.api.DirectoryService;
 import org.apache.directory.server.core.api.DnFactory;
 import org.apache.directory.server.core.api.InstanceLayout;
+import org.apache.directory.server.core.api.event.EventType;
+import org.apache.directory.server.core.api.event.NotificationCriteria;
 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
 import org.apache.directory.server.core.api.partition.Partition;
 import org.apache.directory.server.core.api.schema.SchemaPartition;
@@ -202,6 +205,19 @@ public class ApacheDsService
 
         // start the jetty http server
         startHttpServer( directoryServiceBean.getHttpServerBean(), directoryService );
+        
+        LOG.info( "Registering config change listener" );
+        ConfigChangeListener configListener = new ConfigChangeListener( cpReader, directoryService );
+
+        NotificationCriteria criteria = new NotificationCriteria();
+        criteria.setBase( configPartition.getSuffixDn() );
+        criteria.setEventMask( EventType.ALL_EVENT_TYPES_MASK );
+        
+        PresenceNode filter = new PresenceNode( SchemaConstants.OBJECT_CLASS_AT );
+        criteria.setFilter( filter );
+        criteria.setScope( SearchScope.SUBTREE );
+        
+        directoryService.getEventService().addListener( configListener, criteria );
     }