1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.operations.modify;
21  
22  
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import javax.naming.NamingEnumeration;
29  import javax.naming.directory.Attribute;
30  import javax.naming.directory.BasicAttribute;
31  import javax.naming.directory.DirContext;
32  import javax.naming.directory.ModificationItem;
33  import javax.naming.directory.SearchControls;
34  import javax.naming.directory.SearchResult;
35  
36  import org.apache.directory.server.core.DefaultDirectoryService;
37  import org.apache.directory.server.core.DirectoryService;
38  import org.apache.directory.server.core.entry.ServerEntry;
39  import org.apache.directory.server.core.integ.IntegrationUtils;
40  import org.apache.directory.server.core.integ.Level;
41  import org.apache.directory.server.core.integ.annotations.ApplyLdifs;
42  import org.apache.directory.server.core.integ.annotations.CleanupLevel;
43  import org.apache.directory.server.core.integ.annotations.Factory;
44  import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;
45  import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
46  import org.apache.directory.server.integ.LdapServerFactory;
47  import org.apache.directory.server.integ.SiRunner;
48  import static org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContext;
49  
50  import org.apache.directory.server.ldap.LdapService;
51  import org.apache.directory.server.ldap.handlers.bind.MechanismHandler;
52  import org.apache.directory.server.ldap.handlers.bind.SimpleMechanismHandler;
53  import org.apache.directory.server.ldap.handlers.bind.cramMD5.CramMd5MechanismHandler;
54  import org.apache.directory.server.ldap.handlers.bind.digestMD5.DigestMd5MechanismHandler;
55  import org.apache.directory.server.ldap.handlers.bind.gssapi.GssapiMechanismHandler;
56  import org.apache.directory.server.ldap.handlers.bind.ntlm.NtlmMechanismHandler;
57  import org.apache.directory.server.ldap.handlers.extended.StartTlsHandler;
58  import org.apache.directory.server.ldap.handlers.extended.StoredProcedureExtendedOperationHandler;
59  import org.apache.directory.server.protocol.shared.SocketAcceptor;
60  import org.apache.directory.server.xdbm.Index;
61  import org.apache.directory.shared.ldap.constants.SchemaConstants;
62  import org.apache.directory.shared.ldap.constants.SupportedSaslMechanisms;
63  import org.apache.mina.util.AvailablePortFinder;
64  import org.junit.Test;
65  import org.junit.runner.RunWith;
66  import static org.junit.Assert.assertTrue;
67  import static org.junit.Assert.assertNotNull;
68  
69  
70  /**
71   * Test case for all modify replace operations.
72   * 
73   * Demonstrates DIRSERVER-646 ("Replacing an unknown attribute with
74   * no values (deletion) causes an error").
75   */
76  @RunWith ( SiRunner.class ) 
77  @CleanupLevel ( Level.SUITE )
78  @Factory ( ModifyReplaceIT.Factory.class )
79  @ApplyLdifs( {
80      // Entry # 1
81      "dn: cn=Kate Bush,ou=system\n" +
82      "objectClass: top\n" +
83      "objectClass: person\n" +
84      "sn: Bush\n" +
85      "cn: Kate Bush\n\n" +
86  
87      // Entry # 2
88      "dn: cn=Kim Wilde,ou=system\n" +
89      "objectClass: top\n" +
90      "objectClass: person\n" +
91      "objectClass: organizationalPerson \n" +
92      "objectClass: inetOrgPerson \n" +
93      "sn: Wilde\n" +
94      "cn: Kim Wilde\n\n" 
95      }
96  )
97  public class ModifyReplaceIT 
98  {
99      private static final String BASE = "ou=system";
100 
101     public static LdapService ldapService;
102     
103     
104     public static class Factory implements LdapServerFactory
105     {
106         public LdapService newInstance() throws Exception
107         {
108             DirectoryService service = new DefaultDirectoryService();
109             IntegrationUtils.doDelete( service.getWorkingDirectory() );
110             service.getChangeLog().setEnabled( true );
111             service.setShutdownHookEnabled( false );
112 
113             JdbmPartition system = new JdbmPartition();
114             system.setId( "system" );
115 
116             // @TODO need to make this configurable for the system partition
117             system.setCacheSize( 500 );
118 
119             system.setSuffix( "ou=system" );
120 
121             // Add indexed attributes for system partition
122             Set<Index<?,ServerEntry>> indexedAttrs = new HashSet<Index<?,ServerEntry>>();
123             indexedAttrs.add( new JdbmIndex<String,ServerEntry>( SchemaConstants.OBJECT_CLASS_AT ) );
124             indexedAttrs.add( new JdbmIndex<String,ServerEntry>( SchemaConstants.OU_AT ) );
125             system.setIndexedAttributes( indexedAttrs );
126             service.setSystemPartition( system );
127 
128             // change the working directory to something that is unique
129             // on the system and somewhere either under target directory
130             // or somewhere in a temp area of the machine.
131 
132             LdapService ldapService = new LdapService();
133             ldapService.setDirectoryService( service );
134             ldapService.setSocketAcceptor( new SocketAcceptor( null ) );
135             ldapService.setIpPort( AvailablePortFinder.getNextAvailable( 1024 ) );
136             ldapService.addExtendedOperationHandler( new StartTlsHandler() );
137             ldapService.addExtendedOperationHandler( new StoredProcedureExtendedOperationHandler() );
138 
139             // Setup SASL Mechanisms
140             
141             Map<String, MechanismHandler> mechanismHandlerMap = new HashMap<String,MechanismHandler>();
142             mechanismHandlerMap.put( SupportedSaslMechanisms.PLAIN, new SimpleMechanismHandler() );
143 
144             CramMd5MechanismHandler cramMd5MechanismHandler = new CramMd5MechanismHandler();
145             mechanismHandlerMap.put( SupportedSaslMechanisms.CRAM_MD5, cramMd5MechanismHandler );
146 
147             DigestMd5MechanismHandler digestMd5MechanismHandler = new DigestMd5MechanismHandler();
148             mechanismHandlerMap.put( SupportedSaslMechanisms.DIGEST_MD5, digestMd5MechanismHandler );
149 
150             GssapiMechanismHandler gssapiMechanismHandler = new GssapiMechanismHandler();
151             mechanismHandlerMap.put( SupportedSaslMechanisms.GSSAPI, gssapiMechanismHandler );
152 
153             NtlmMechanismHandler ntlmMechanismHandler = new NtlmMechanismHandler();
154             mechanismHandlerMap.put( SupportedSaslMechanisms.NTLM, ntlmMechanismHandler );
155             mechanismHandlerMap.put( SupportedSaslMechanisms.GSS_SPNEGO, ntlmMechanismHandler );
156 
157             ldapService.setSaslMechanismHandlers( mechanismHandlerMap );
158 
159             return ldapService;
160         }
161     }
162     
163     /**
164      * Create a person entry and try to remove a not present attribute
165      */
166     @Test
167     public void testReplaceNotPresentAttribute() throws Exception 
168     {
169         DirContext sysRoot = ( DirContext ) getWiredContext( ldapService ).lookup( BASE );
170         
171         String rdn = "cn=Kate Bush";
172 
173         Attribute attr = new BasicAttribute( "description" );
174         ModificationItem item = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
175 
176         sysRoot.modifyAttributes( rdn, new ModificationItem[] { item } );
177 
178         SearchControls sctls = new SearchControls();
179         sctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
180         String filter = "(sn=Bush)";
181         String base = "";
182 
183         NamingEnumeration<SearchResult> enm = sysRoot.search( base, filter, sctls );
184         while ( enm.hasMore() ) 
185         {
186             SearchResult sr = ( SearchResult ) enm.next();
187             Attribute cn = sr.getAttributes().get( "cn" );
188             assertNotNull( cn );
189             assertTrue( cn.contains("Kate Bush") );
190         }
191 
192         sysRoot.destroySubcontext( rdn );
193     }
194 
195     
196     /**
197      * Create a person entry and try to remove a non existing attribute
198      */
199     @Test
200     public void testReplaceNonExistingAttribute() throws Exception 
201     {
202         DirContext sysRoot = ( DirContext ) getWiredContext( ldapService ).lookup( BASE );
203         
204         String rdn = "cn=Kate Bush";
205 
206         Attribute attr = new BasicAttribute( "numberOfOctaves" );
207         ModificationItem item = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
208 
209         sysRoot.modifyAttributes(rdn, new ModificationItem[] { item });
210 
211         SearchControls sctls = new SearchControls();
212         sctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
213         String filter = "(sn=Bush)";
214         String base = "";
215 
216         NamingEnumeration<SearchResult> enm = sysRoot.search( base, filter, sctls );
217         while ( enm.hasMore() ) 
218         {
219             SearchResult sr = enm.next();
220             Attribute cn = sr.getAttributes().get( "cn" );
221             assertNotNull( cn );
222             assertTrue( cn.contains( "Kate Bush" ) );
223         }
224 
225         sysRoot.destroySubcontext( rdn );
226     }
227 
228 
229     /**
230      * Create a person entry and try to remove a non existing attribute
231      */
232     @Test
233     public void testReplaceNonExistingAttributeManyMods() throws Exception 
234     {
235         DirContext sysRoot = ( DirContext ) getWiredContext( ldapService ).lookup( BASE );
236         
237         String rdn = "cn=Kate Bush";
238 
239         Attribute attr = new BasicAttribute( "numberOfOctaves" );
240         ModificationItem item = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
241         Attribute attr2 = new BasicAttribute( "description", "blah blah blah" );
242         ModificationItem item2 = new ModificationItem( DirContext.ADD_ATTRIBUTE, attr2 );
243 
244         sysRoot.modifyAttributes(rdn, new ModificationItem[] { item, item2 });
245 
246         SearchControls sctls = new SearchControls();
247         sctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
248         String filter = "(sn=Bush)";
249         String base = "";
250 
251         NamingEnumeration<SearchResult> enm = sysRoot.search( base, filter, sctls );
252         while ( enm.hasMore() ) 
253         {
254             SearchResult sr = enm.next();
255             Attribute cn = sr.getAttributes().get( "cn" );
256             assertNotNull( cn );
257             assertTrue( cn.contains( "Kate Bush" ) );
258         }
259 
260         sysRoot.destroySubcontext( rdn );
261     }
262 
263 
264     /**
265      * Create a person entry and try to replace a non existing indexed attribute
266      */
267     @Test
268     public void testReplaceNonExistingIndexedAttribute() throws Exception 
269     {
270         DirContext sysRoot = ( DirContext ) getWiredContext( ldapService ).lookup( BASE );
271         
272         String rdn = "cn=Kim Wilde";
273         //ldapService.getDirectoryService().getPartitions();
274 
275         Attribute attr = new BasicAttribute( "ou", "test" );
276         ModificationItem item = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
277 
278         sysRoot.modifyAttributes(rdn, new ModificationItem[] { item });
279 
280         SearchControls sctls = new SearchControls();
281         sctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
282         String filter = "(sn=Wilde)";
283         String base = "";
284 
285         NamingEnumeration<SearchResult> enm = sysRoot.search( base, filter, sctls );
286         
287         while ( enm.hasMore() ) 
288         {
289             SearchResult sr = enm.next();
290             Attribute ou = sr.getAttributes().get( "ou" );
291             assertNotNull( ou );
292             assertTrue( ou.contains( "test" ) );
293         }
294 
295         sysRoot.destroySubcontext( rdn );
296     }
297 }