001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 021package org.apache.directory.server.config.listener; 022 023 024import static org.apache.directory.server.core.api.InterceptorEnum.AUTHENTICATION_INTERCEPTOR; 025 026import org.apache.directory.api.ldap.model.entry.Attribute; 027import org.apache.directory.api.ldap.model.entry.DefaultAttribute; 028import org.apache.directory.api.ldap.model.entry.Entry; 029import org.apache.directory.api.ldap.model.exception.LdapException; 030import org.apache.directory.api.ldap.model.name.Dn; 031import org.apache.directory.api.ldap.model.schema.AttributeType; 032import org.apache.directory.api.ldap.model.schema.SchemaManager; 033import org.apache.directory.server.config.ConfigPartitionReader; 034import org.apache.directory.server.config.beans.PasswordPolicyBean; 035import org.apache.directory.server.config.builder.ServiceBuilder; 036import org.apache.directory.server.core.api.DirectoryService; 037import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyConfiguration; 038import org.apache.directory.server.core.api.event.DirectoryListenerAdapter; 039import org.apache.directory.server.core.api.interceptor.context.AddOperationContext; 040import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext; 041import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext; 042import org.apache.directory.server.core.authn.AuthenticationInterceptor; 043import org.apache.directory.server.core.authn.ppolicy.PpolicyConfigContainer; 044import org.slf4j.Logger; 045import org.slf4j.LoggerFactory; 046 047 048/** 049 * A listener for handling the config partition changes. 050 * 051 * Note: currently handles password policy related configuration changes only. 052 * 053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 054 */ 055public class ConfigChangeListener extends DirectoryListenerAdapter 056{ 057 /** the config parition reader */ 058 private ConfigPartitionReader cpReader; 059 060 /** container holding the current active password policy configurations */ 061 private PpolicyConfigContainer ppolicyConfigContainer; 062 063 /** the root DN of password policy configurations */ 064 private Dn ppolicyConfigDnRoot; 065 066 private static final String PPOLICY_OC_NAME = "ads-passwordPolicy"; 067 068 // attribute holding the value of #PPOLICY_OC_NAME 069 private Attribute passwordPolicyObjectClassAttribute; 070 071 072 /** The logger for this class */ 073 private static final Logger LOG = LoggerFactory.getLogger( ConfigChangeListener.class ); 074 075 /** 076 * 077 * Creates a new instance of ConfigChangeListener. 078 * 079 * @param cpReader the configuration reader 080 * @param directoryService the DirectoryService instance 081 * @throws LdapException If the instance cannot be created 082 */ 083 public ConfigChangeListener( ConfigPartitionReader cpReader, DirectoryService directoryService ) 084 throws LdapException 085 { 086 this.cpReader = cpReader; 087 088 SchemaManager schemaManager = directoryService.getSchemaManager(); 089 090 ppolicyConfigDnRoot = new Dn( schemaManager, 091 "ou=passwordPolicies,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config" ); 092 093 AuthenticationInterceptor authInterceptor = ( AuthenticationInterceptor ) directoryService 094 .getInterceptor( AUTHENTICATION_INTERCEPTOR.getName() ); 095 ppolicyConfigContainer = authInterceptor.getPwdPolicyContainer(); 096 097 AttributeType ocType = directoryService.getAtProvider().getObjectClass(); 098 passwordPolicyObjectClassAttribute = new DefaultAttribute( ocType, PPOLICY_OC_NAME ); 099 } 100 101 102 @Override 103 public void entryAdded( AddOperationContext addContext ) 104 { 105 Entry entry = addContext.getEntry(); 106 updatePasswordPolicy( entry, false ); 107 } 108 109 110 @Override 111 public void entryDeleted( DeleteOperationContext deleteContext ) 112 { 113 Entry entry = deleteContext.getEntry(); 114 updatePasswordPolicy( entry, true ); 115 } 116 117 118 @Override 119 public void entryModified( ModifyOperationContext modifyContext ) 120 { 121 Entry entry = modifyContext.getAlteredEntry(); 122 updatePasswordPolicy( entry, false ); 123 } 124 125 126 /** 127 * Updates the password policy represented by the given configuration entry 128 * 129 * @param entry the password policy configuration entry 130 * @param deleted flag to detect if this is a deleted entry 131 */ 132 private void updatePasswordPolicy( Entry entry, boolean deleted ) 133 { 134 Dn dn = entry.getDn(); 135 136 if ( !dn.isDescendantOf( ppolicyConfigDnRoot ) ) 137 { 138 return; 139 } 140 141 if ( !entry.contains( passwordPolicyObjectClassAttribute ) ) 142 { 143 return; 144 } 145 146 if ( deleted ) 147 { 148 LOG.debug( "Deleting ppolicy config {}", dn ); 149 ppolicyConfigContainer.removePolicyConfig( dn ); 150 return; 151 } 152 153 PasswordPolicyBean bean = null; 154 155 try 156 { 157 bean = ( PasswordPolicyBean ) cpReader.readConfig( entry ); 158 } 159 catch ( Exception e ) 160 { 161 LOG.warn( "Failed to read the updated ppolicy configuration from {}", dn ); 162 LOG.warn( "", e ); 163 return; 164 } 165 166 if ( bean.isDisabled() ) 167 { 168 LOG.debug( "Deleting disabled ppolicy config {}", dn ); 169 ppolicyConfigContainer.removePolicyConfig( dn ); 170 } 171 else 172 { 173 PasswordPolicyConfiguration updated = ServiceBuilder.createPwdPolicyConfig( bean ); 174 175 PasswordPolicyConfiguration existing = ppolicyConfigContainer.getPolicyConfig( dn ); 176 177 if ( existing == null ) 178 { 179 LOG.debug( "Adding ppolicy config {}", dn ); 180 } 181 else 182 { 183 LOG.debug( "Updating ppolicy config {}", dn ); 184 } 185 186 ppolicyConfigContainer.addPolicy( dn, updated ); 187 } 188 } 189}