1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.operations.bind;
21
22
23 import java.util.HashMap;
24 import java.util.Hashtable;
25 import java.util.Map;
26
27 import javax.naming.Context;
28 import javax.naming.NamingEnumeration;
29 import javax.naming.NamingException;
30 import javax.naming.NoPermissionException;
31 import javax.naming.OperationNotSupportedException;
32 import javax.naming.directory.Attribute;
33 import javax.naming.directory.Attributes;
34 import javax.naming.directory.BasicAttribute;
35 import javax.naming.directory.BasicAttributes;
36 import javax.naming.directory.DirContext;
37 import javax.naming.directory.InitialDirContext;
38 import javax.naming.directory.SearchControls;
39 import javax.naming.directory.SearchResult;
40 import javax.naming.ldap.InitialLdapContext;
41
42 import org.apache.directory.server.core.DefaultDirectoryService;
43 import org.apache.directory.server.core.DirectoryService;
44 import org.apache.directory.server.core.integ.IntegrationUtils;
45 import org.apache.directory.server.core.integ.Level;
46 import org.apache.directory.server.core.integ.annotations.ApplyLdifs;
47 import org.apache.directory.server.core.integ.annotations.CleanupLevel;
48 import org.apache.directory.server.core.integ.annotations.Factory;
49 import org.apache.directory.server.integ.LdapServerFactory;
50 import org.apache.directory.server.integ.SiRunner;
51 import org.apache.directory.server.ldap.LdapService;
52 import org.apache.directory.server.ldap.handlers.bind.MechanismHandler;
53 import org.apache.directory.server.ldap.handlers.bind.SimpleMechanismHandler;
54 import org.apache.directory.server.ldap.handlers.bind.cramMD5.CramMd5MechanismHandler;
55 import org.apache.directory.server.ldap.handlers.bind.digestMD5.DigestMd5MechanismHandler;
56 import org.apache.directory.server.ldap.handlers.bind.gssapi.GssapiMechanismHandler;
57 import org.apache.directory.server.ldap.handlers.bind.ntlm.NtlmMechanismHandler;
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.core.partition.impl.btree.jdbm.JdbmPartition;
61 import org.apache.directory.shared.asn1.util.Asn1StringUtils;
62 import org.apache.directory.shared.ldap.constants.SupportedSaslMechanisms;
63 import org.apache.directory.shared.ldap.message.MutableControl;
64 import org.apache.directory.shared.ldap.util.ArrayUtils;
65 import org.apache.mina.util.AvailablePortFinder;
66 import org.junit.After;
67 import org.junit.Before;
68 import org.junit.Test;
69 import org.junit.runner.RunWith;
70
71 import static org.junit.Assert.fail;
72 import static org.junit.Assert.assertEquals;
73 import static org.junit.Assert.assertTrue;
74 import static org.junit.Assert.assertFalse;
75 import static org.junit.Assert.assertNotNull;
76
77
78
79
80
81
82
83
84 @RunWith ( SiRunner.class )
85 @CleanupLevel ( Level.CLASS )
86 @Factory ( MiscBindIT.Factory.class )
87 @ApplyLdifs( {
88
89 "dn: dc=aPache,dc=org\n" +
90 "dc: aPache\n" +
91 "objectClass: top\n" +
92 "objectClass: domain\n\n"
93 }
94 )
95 public class MiscBindIT
96 {
97 public static LdapService ldapService;
98
99
100 public static class Factory implements LdapServerFactory
101 {
102 public LdapService newInstance() throws Exception
103 {
104 DirectoryService service = new DefaultDirectoryService();
105 IntegrationUtils.doDelete( service.getWorkingDirectory() );
106 service.getChangeLog().setEnabled( true );
107 service.setAllowAnonymousAccess( true );
108 service.setShutdownHookEnabled( false );
109
110 JdbmPartition apache = new JdbmPartition();
111 apache.setId( "apache" );
112
113
114 apache.setCacheSize( 500 );
115 apache.setSuffix( "dc=aPache,dc=org" );
116 apache.setId( "apache" );
117 service.addPartition( apache );
118
119
120
121
122
123 LdapService ldapService = new LdapService();
124 ldapService.setDirectoryService( service );
125 ldapService.setSocketAcceptor( new SocketAcceptor( null ) );
126 ldapService.setIpPort( AvailablePortFinder.getNextAvailable( 1024 ) );
127 ldapService.setAllowAnonymousAccess( true );
128 ldapService.addExtendedOperationHandler( new StoredProcedureExtendedOperationHandler() );
129
130
131
132 Map<String, MechanismHandler> mechanismHandlerMap = new HashMap<String,MechanismHandler>();
133 mechanismHandlerMap.put( SupportedSaslMechanisms.PLAIN, new SimpleMechanismHandler() );
134
135 CramMd5MechanismHandler cramMd5MechanismHandler = new CramMd5MechanismHandler();
136 mechanismHandlerMap.put( SupportedSaslMechanisms.CRAM_MD5, cramMd5MechanismHandler );
137
138 DigestMd5MechanismHandler digestMd5MechanismHandler = new DigestMd5MechanismHandler();
139 mechanismHandlerMap.put( SupportedSaslMechanisms.DIGEST_MD5, digestMd5MechanismHandler );
140
141 GssapiMechanismHandler gssapiMechanismHandler = new GssapiMechanismHandler();
142 mechanismHandlerMap.put( SupportedSaslMechanisms.GSSAPI, gssapiMechanismHandler );
143
144 NtlmMechanismHandler ntlmMechanismHandler = new NtlmMechanismHandler();
145 mechanismHandlerMap.put( SupportedSaslMechanisms.NTLM, ntlmMechanismHandler );
146 mechanismHandlerMap.put( SupportedSaslMechanisms.GSS_SPNEGO, ntlmMechanismHandler );
147
148 ldapService.setSaslMechanismHandlers( mechanismHandlerMap );
149
150 return ldapService;
151 }
152 }
153
154
155
156 private boolean oldAnnonymousAccess;
157
158
159 @Before
160 public void recordAnnonymous() throws NamingException
161 {
162 oldAnnonymousAccess = ldapService.getDirectoryService().isAllowAnonymousAccess();
163 }
164
165
166 @After
167 public void revertAnonnymous()
168 {
169 ldapService.getDirectoryService().setAllowAnonymousAccess( oldAnnonymousAccess );
170 ldapService.setAllowAnonymousAccess( oldAnnonymousAccess );
171 }
172
173
174
175
176
177
178
179
180 @Test
181 public void testDisableAnonymousBinds() throws Exception
182 {
183 ldapService.getDirectoryService().setAllowAnonymousAccess( false );
184 ldapService.setAllowAnonymousAccess( false );
185
186
187 InitialDirContext ic = null;
188 final Hashtable<String, Object> env = new Hashtable<String, Object>();
189
190 env.put( Context.PROVIDER_URL, "ldap://localhost:" + ldapService.getIpPort() + "/ou=system" );
191 env.put( Context.SECURITY_AUTHENTICATION, "none" );
192 env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
193
194 boolean connected = false;
195 while ( !connected )
196 {
197 try
198 {
199 ic = new InitialDirContext( env );
200 connected = true;
201 }
202 catch ( Exception e )
203 {
204
205 fail();
206 }
207 }
208
209 ldapService.getDirectoryService().setAllowAnonymousAccess( false );
210
211 try
212 {
213 ic.search( "", "(objectClass=*)", new SearchControls() );
214 fail( "If anonymous binds are disabled we should never get here!" );
215 }
216 catch ( NoPermissionException e )
217 {
218 }
219
220 Attributes attrs = new BasicAttributes( true );
221 Attribute oc = new BasicAttribute( "objectClass" );
222 attrs.put( oc );
223 oc.add( "top" );
224 oc.add( "organizationalUnit" );
225
226 try
227 {
228 ic.createSubcontext( "ou=blah", attrs );
229 }
230 catch ( NoPermissionException e )
231 {
232 }
233 }
234
235
236
237
238
239
240
241
242 @Test
243 public void testEnableAnonymousBindsOnRootDSE() throws Exception
244 {
245 ldapService.getDirectoryService().setAllowAnonymousAccess( true );
246
247
248 Hashtable<String, Object> env = new Hashtable<String, Object>();
249
250 env.put( Context.PROVIDER_URL, "ldap://localhost:" + ldapService.getIpPort() + "/" );
251 env.put( Context.SECURITY_AUTHENTICATION, "none" );
252 env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
253
254 InitialDirContext ctx = new InitialDirContext( env );
255 SearchControls cons = new SearchControls();
256 cons.setSearchScope( SearchControls.OBJECT_SCOPE );
257 NamingEnumeration<SearchResult> list = ctx.search( "", "(objectClass=*)", cons );
258
259 SearchResult result = null;
260
261 if ( list.hasMore() )
262 {
263 result = list.next();
264 }
265
266 assertFalse( list.hasMore() );
267 list.close();
268
269 assertNotNull( result );
270 assertEquals( "", result.getName().trim() );
271 }
272
273
274
275
276
277
278
279
280 @Test
281 public void testAnonymousBindsEnabledBaseSearch() throws Exception
282 {
283 ldapService.getDirectoryService().setAllowAnonymousAccess( true );
284
285
286 Hashtable<String, Object> env = new Hashtable<String, Object>();
287
288 env.put( Context.PROVIDER_URL, "ldap://localhost:" + ldapService.getIpPort() + "/" );
289 env.put( Context.SECURITY_AUTHENTICATION, "none" );
290 env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
291
292 InitialDirContext ctx = new InitialDirContext( env );
293 SearchControls cons = new SearchControls();
294 cons.setSearchScope( SearchControls.OBJECT_SCOPE );
295 NamingEnumeration<SearchResult> list = ctx.search( "dc=apache,dc=org", "(objectClass=*)", cons );
296 SearchResult result = null;
297
298 if ( list.hasMore() )
299 {
300 result = list.next();
301 }
302
303 assertFalse( list.hasMore() );
304 list.close();
305
306 assertNotNull( result );
307 assertNotNull( result.getAttributes().get( "dc" ) );
308 }
309
310
311
312
313
314
315
316
317 @Test
318 public void testAdminAccessBug() throws Exception
319 {
320 ldapService.getDirectoryService().setAllowAnonymousAccess( true );
321
322
323
324 final Hashtable<String, Object> env = new Hashtable<String, Object>();
325
326 env.put( Context.PROVIDER_URL, "ldap://localhost:" + ldapService.getIpPort() );
327 env.put( "java.naming.ldap.version", "3" );
328 env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
329
330 Attributes attributes = new BasicAttributes( true );
331 Attribute objectClass = new BasicAttribute( "objectClass" );
332 objectClass.add( "top" );
333 objectClass.add( "organizationalUnit" );
334 attributes.put( objectClass );
335 attributes.put( "ou", "blah" );
336 InitialDirContext ctx = new InitialDirContext( env );
337 ctx.createSubcontext( "ou=blah,ou=system", attributes );
338 SearchControls controls = new SearchControls();
339 controls.setSearchScope( SearchControls.OBJECT_SCOPE );
340 controls.setReturningAttributes( new String[]
341 {"+"} );
342 NamingEnumeration<SearchResult> list = ctx.search( "ou=blah,ou=system", "(objectClass=*)", controls );
343 SearchResult result = list.next();
344 list.close();
345 Attribute creatorsName = result.getAttributes().get( "creatorsName" );
346 assertEquals( "", creatorsName.get() );
347 }
348
349
350
351
352
353
354
355
356
357
358 @Test
359 public void testUserAuthOnMixedCaseSuffix() throws Exception
360 {
361 ldapService.getDirectoryService().setAllowAnonymousAccess( true );
362
363 Hashtable<String, Object> env = new Hashtable<String, Object>();
364
365 env.put( Context.PROVIDER_URL, "ldap://localhost:" + ldapService.getIpPort() + "/dc=aPache,dc=org" );
366 env.put( "java.naming.ldap.version", "3" );
367 env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
368 InitialDirContext ctx = new InitialDirContext( env );
369 Attributes attrs = ctx.getAttributes( "" );
370 assertTrue( attrs.get( "dc" ).get().equals( "aPache" ) );
371
372 Attributes user = new BasicAttributes( "cn", "Kate Bush", true );
373 Attribute oc = new BasicAttribute( "objectClass" );
374 oc.add( "top" );
375 oc.add( "person" );
376 oc.add( "organizationalPerson" );
377 oc.add( "inetOrgPerson" );
378 user.put( oc );
379 user.put( "sn", "Bush" );
380 user.put( "userPassword", "Aerial" );
381 ctx.createSubcontext( "cn=Kate Bush", user );
382
383 env.put( Context.SECURITY_AUTHENTICATION, "simple" );
384 env.put( Context.SECURITY_CREDENTIALS, "Aerial" );
385 env.put( Context.SECURITY_PRINCIPAL, "cn=Kate Bush,dc=aPache,dc=org" );
386
387 InitialDirContext userCtx = new InitialDirContext( env );
388 assertNotNull( userCtx );
389 }
390
391
392 @Test
393 public void testFailureWithUnsupportedControl() throws Exception
394 {
395 MutableControl unsupported = new MutableControl()
396 {
397 boolean isCritical = true;
398 private static final long serialVersionUID = 1L;
399
400
401 @SuppressWarnings("unused")
402 public String getType()
403 {
404 return "1.1.1.1";
405 }
406
407
408 public void setID( String oid )
409 {
410 }
411
412
413 @SuppressWarnings("unused")
414 public byte[] getValue()
415 {
416 return new byte[0];
417 }
418
419
420 @SuppressWarnings("unused")
421 public void setValue( byte[] value )
422 {
423 }
424
425
426 public boolean isCritical()
427 {
428 return isCritical;
429 }
430
431
432 public void setCritical( boolean isCritical )
433 {
434 this.isCritical = isCritical;
435 }
436
437
438 public String getID()
439 {
440 return "1.1.1.1";
441 }
442
443
444 public byte[] getEncodedValue()
445 {
446 return new byte[0];
447 }
448 };
449
450 ldapService.getDirectoryService().setAllowAnonymousAccess( true );
451
452 Hashtable<String, Object> env = new Hashtable<String, Object>();
453
454 env.put( Context.PROVIDER_URL, "ldap://localhost:" + ldapService.getIpPort() + "/ou=system" );
455 env.put( "java.naming.ldap.version", "3" );
456 env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
457 env.put( Context.SECURITY_AUTHENTICATION, "simple" );
458 env.put( Context.SECURITY_CREDENTIALS, "secret" );
459 env.put( Context.SECURITY_PRINCIPAL, "uid=admin,ou=system" );
460 InitialLdapContext ctx = new InitialLdapContext( env, null );
461
462 Attributes user = new BasicAttributes( "cn", "Kate Bush", true );
463 Attribute oc = new BasicAttribute( "objectClass" );
464 oc.add( "top" );
465 oc.add( "person" );
466 oc.add( "organizationalPerson" );
467 oc.add( "inetOrgPerson" );
468 user.put( oc );
469 user.put( "sn", "Bush" );
470 user.put( "userPassword", "Aerial" );
471 ctx.setRequestControls( new MutableControl[]
472 {unsupported} );
473
474 try
475 {
476 ctx.createSubcontext( "cn=Kate Bush", user );
477 }
478 catch ( OperationNotSupportedException e )
479 {
480 }
481
482 unsupported.setCritical( false );
483 DirContext kate = ctx.createSubcontext( "cn=Kate Bush", user );
484 assertNotNull( kate );
485 assertTrue( ArrayUtils.isEquals( Asn1StringUtils.getBytesUtf8( "Aerial" ), kate.getAttributes( "" ).get(
486 "userPassword" ).get() ) );
487 }
488 }