1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.ldap.server.jndi;
18
19 import java.util.Hashtable;
20 import java.util.Iterator;
21
22 import javax.naming.Context;
23 import javax.naming.Name;
24 import javax.naming.NamingException;
25 import javax.naming.NoPermissionException;
26 import javax.naming.directory.Attribute;
27 import javax.naming.directory.Attributes;
28
29 import org.apache.ldap.common.exception.LdapAuthenticationNotSupportedException;
30 import org.apache.ldap.common.exception.LdapConfigurationException;
31 import org.apache.ldap.common.exception.LdapNoPermissionException;
32 import org.apache.ldap.common.message.LockableAttributesImpl;
33 import org.apache.ldap.common.message.ResultCodeEnum;
34 import org.apache.ldap.common.message.LockableAttributeImpl;
35 import org.apache.ldap.common.name.DnParser;
36 import org.apache.ldap.common.name.LdapName;
37 import org.apache.ldap.common.name.NameComponentNormalizer;
38 import org.apache.ldap.common.util.DateUtils;
39 import org.apache.ldap.server.configuration.Configuration;
40 import org.apache.ldap.server.configuration.ConfigurationException;
41 import org.apache.ldap.server.configuration.StartupConfiguration;
42 import org.apache.ldap.server.interceptor.InterceptorChain;
43 import org.apache.ldap.server.partition.ContextPartitionNexus;
44 import org.apache.ldap.server.partition.DefaultContextPartitionNexus;
45 import org.apache.ldap.server.schema.AttributeTypeRegistry;
46 import org.apache.ldap.server.schema.ConcreteNameComponentNormalizer;
47 import org.apache.ldap.server.schema.GlobalRegistries;
48 import org.apache.ldap.server.schema.bootstrap.BootstrapRegistries;
49 import org.apache.ldap.server.schema.bootstrap.BootstrapSchemaLoader;
50
51
52 /***
53 * Default implementation of {@link ContextFactoryService}.
54 *
55 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
56 * @version $Rev: 264732 $
57 */
58 class DefaultContextFactoryService extends ContextFactoryService
59 {
60 private final String instanceId;
61
62 private final ContextFactoryConfiguration configuration = new DefaultContextFactoryConfiguration( this );
63
64 private ContextFactoryServiceListener serviceListener;
65
66 /*** the initial context environment that fired up the backend subsystem */
67 private Hashtable environment;
68
69 /*** the configuration */
70 private StartupConfiguration startupConfiguration;
71
72 /*** the registries for system schema objects */
73 private GlobalRegistries globalRegistries;
74
75 /*** the root nexus */
76 private DefaultContextPartitionNexus partitionNexus;
77
78 /*** whether or not server is started for the first time */
79 private boolean firstStart;
80
81 /*** The interceptor (or interceptor chain) for this service */
82 private InterceptorChain interceptorChain;
83
84 /*** whether or not this instance has been shutdown */
85 private boolean started = false;
86
87
88
89
90
91
92 /***
93 * Creates a new instance.
94 */
95 public DefaultContextFactoryService( String instanceId )
96 {
97 if( instanceId == null )
98 {
99 throw new NullPointerException( "instanceId" );
100 }
101
102 this.instanceId = instanceId;
103
104
105 Runtime.getRuntime().addShutdownHook( new Thread( new Runnable() {
106 public void run()
107 {
108 try
109 {
110 shutdown();
111 }
112 catch( NamingException e )
113 {
114 e.printStackTrace();
115 }
116 }
117 }, "ApacheDS Shutdown Hook" ) );
118 }
119
120
121
122
123
124 public Context getJndiContext( String rootDN ) throws NamingException
125 {
126 return this.getJndiContext( null, null, "none", rootDN );
127 }
128
129 public synchronized Context getJndiContext( String principal, byte[] credential, String authentication, String rootDN ) throws NamingException
130 {
131 checkSecuritySettings( principal, credential, authentication );
132
133 if ( !started )
134 {
135 return new DeadContext();
136 }
137
138 Hashtable environment = getEnvironment();
139 environment.remove( Context.SECURITY_PRINCIPAL );
140 environment.remove( Context.SECURITY_CREDENTIALS );
141 environment.remove( Context.SECURITY_AUTHENTICATION );
142
143 if( principal != null )
144 {
145 environment.put( Context.SECURITY_PRINCIPAL, principal );
146 }
147
148 if( credential != null )
149 {
150 environment.put( Context.SECURITY_CREDENTIALS, credential );
151 }
152
153 if( authentication != null )
154 {
155 environment.put( Context.SECURITY_AUTHENTICATION, authentication );
156 }
157
158 if( rootDN == null )
159 {
160 rootDN = "";
161 }
162 environment.put( Context.PROVIDER_URL, rootDN );
163
164 return new ServerLdapContext( this, environment );
165 }
166
167 public synchronized void startup( ContextFactoryServiceListener listener, Hashtable env ) throws NamingException
168 {
169 Hashtable envCopy = ( Hashtable ) env.clone();
170
171 if( started )
172 {
173 return;
174 }
175
176 StartupConfiguration cfg = ( StartupConfiguration ) Configuration.toConfiguration( env );
177 envCopy.put( Context.PROVIDER_URL, "" );
178
179 try
180 {
181 cfg.validate();
182 }
183 catch( ConfigurationException e )
184 {
185 NamingException ne = new LdapConfigurationException( "Invalid configuration." );
186 ne.initCause( e );
187 throw ne;
188 }
189
190 this.environment = envCopy;
191 this.startupConfiguration = cfg;
192
193 listener.beforeStartup( this );
194 try
195 {
196 initialize();
197 firstStart = createBootstrapEntries();
198 createTestEntries();
199 this.serviceListener = listener;
200 started = true;
201 }
202 finally
203 {
204 listener.afterStartup( this );
205 }
206 }
207
208 public synchronized void sync() throws NamingException
209 {
210 if ( !started )
211 {
212 return;
213 }
214
215 serviceListener.beforeSync( this );
216 try
217 {
218 this.partitionNexus.sync();
219 }
220 finally
221 {
222 serviceListener.afterSync( this );
223 }
224 }
225
226
227 public synchronized void shutdown() throws NamingException
228 {
229 if ( !started )
230 {
231 return;
232 }
233
234 serviceListener.beforeShutdown( this );
235 try
236 {
237 this.partitionNexus.sync();
238 this.partitionNexus.destroy();
239 this.interceptorChain.destroy();
240 this.started = false;
241 }
242 finally
243 {
244 environment = null;
245 interceptorChain = null;
246 startupConfiguration = null;
247 serviceListener.afterShutdown( this );
248 }
249 }
250
251 public String getInstanceId()
252 {
253 return instanceId;
254 }
255
256 public ContextFactoryConfiguration getConfiguration()
257 {
258 return configuration;
259 }
260
261
262 public Hashtable getEnvironment()
263 {
264 return ( Hashtable ) environment.clone();
265 }
266
267 public ContextFactoryServiceListener getServiceListener()
268 {
269 return serviceListener;
270 }
271
272 public StartupConfiguration getStartupConfiguration()
273 {
274 return startupConfiguration;
275 }
276
277 public GlobalRegistries getGlobalRegistries()
278 {
279 return globalRegistries;
280 }
281
282 public ContextPartitionNexus getPartitionNexus()
283 {
284 return partitionNexus;
285 }
286
287 public InterceptorChain getInterceptorChain()
288 {
289 return interceptorChain;
290 }
291
292 public boolean isFirstStart()
293 {
294 return firstStart;
295 }
296
297 public boolean isStarted()
298 {
299 return started;
300 }
301
302 /***
303 * Checks to make sure security environment parameters are set correctly.
304 *
305 * @throws javax.naming.NamingException if the security settings are not correctly configured.
306 */
307 private void checkSecuritySettings( String principal, byte[] credential, String authentication ) throws NamingException
308 {
309 if( authentication == null )
310 {
311 authentication = "";
312 }
313
314
315
316
317
318 if ( "simple".equalsIgnoreCase( authentication ) )
319 {
320 if ( credential == null )
321 {
322 throw new LdapConfigurationException( "missing required "
323 + Context.SECURITY_CREDENTIALS + " property for simple authentication" );
324 }
325
326 if ( principal == null )
327 {
328 throw new LdapConfigurationException( "missing required "
329 + Context.SECURITY_PRINCIPAL + " property for simple authentication" );
330 }
331 }
332
333
334
335
336 else if ( "none".equalsIgnoreCase( authentication ) )
337 {
338 if ( credential != null )
339 {
340 throw new LdapConfigurationException( "ambiguous bind "
341 + "settings encountered where bind is anonymous yet "
342 + Context.SECURITY_CREDENTIALS + " property is set" );
343 }
344 if ( principal != null )
345 {
346 throw new LdapConfigurationException( "ambiguous bind "
347 + "settings encountered where bind is anonymous yet "
348 + Context.SECURITY_PRINCIPAL + " property is set" );
349 }
350
351 if( !startupConfiguration.isAllowAnonymousAccess() )
352 {
353 throw new LdapNoPermissionException( "Anonymous access disabled." );
354 }
355 }
356 else
357 {
358
359
360
361
362 throw new LdapAuthenticationNotSupportedException( "Unknown authentication type: '" + authentication + "'", ResultCodeEnum.AUTHMETHODNOTSUPPORTED );
363 }
364 }
365
366
367 /***
368 * Returns true if we had to create the bootstrap entries on the first
369 * start of the server. Otherwise if all entries exist, meaning none
370 * had to be created, then we are not starting for the first time.
371 *
372 * @throws javax.naming.NamingException
373 */
374 private boolean createBootstrapEntries() throws NamingException
375 {
376 boolean firstStart = false;
377
378
379
380
381
382
383
384
385 if ( !partitionNexus.hasEntry( ContextPartitionNexus.getAdminName() ) )
386 {
387 checkPermissionToCreateBootstrapEntries();
388 firstStart = true;
389
390 Attributes attributes = new LockableAttributesImpl();
391 Attribute objectClass = new LockableAttributeImpl( "objectClass" );
392 objectClass.add( "top" );
393 objectClass.add( "person" );
394 objectClass.add( "organizationalPerson" );
395 objectClass.add( "inetOrgPerson" );
396 attributes.put( objectClass );
397
398 attributes.put( "uid", ContextPartitionNexus.ADMIN_UID );
399 attributes.put( "userPassword", environment.get( Context.SECURITY_CREDENTIALS ) );
400 attributes.put( "displayName", "Directory Superuser" );
401 attributes.put( "cn", "system administrator" );
402 attributes.put( "sn", "administrator" );
403 attributes.put( "creatorsName", ContextPartitionNexus.ADMIN_PRINCIPAL );
404 attributes.put( "createTimestamp", DateUtils.getGeneralizedTime() );
405 attributes.put( "displayName", "Directory Superuser" );
406
407 partitionNexus.add( ContextPartitionNexus.ADMIN_PRINCIPAL, ContextPartitionNexus.getAdminName(), attributes );
408 }
409
410
411
412
413
414 if ( !partitionNexus.hasEntry( new LdapName( "ou=users,ou=system" ) ) )
415 {
416 firstStart = true;
417 checkPermissionToCreateBootstrapEntries();
418
419 Attributes attributes = new LockableAttributesImpl();
420 Attribute objectClass = new LockableAttributeImpl( "objectClass" );
421 objectClass.add( "top" );
422 objectClass.add( "organizationalUnit" );
423 attributes.put( objectClass );
424
425 attributes.put( "ou", "users" );
426 attributes.put( "creatorsName", ContextPartitionNexus.ADMIN_PRINCIPAL );
427 attributes.put( "createTimestamp", DateUtils.getGeneralizedTime() );
428
429 partitionNexus.add( "ou=users,ou=system", new LdapName( "ou=users,ou=system" ), attributes );
430 }
431
432
433
434
435
436 if ( !partitionNexus.hasEntry( new LdapName( "ou=groups,ou=system" ) ) )
437 {
438 firstStart = true;
439 checkPermissionToCreateBootstrapEntries();
440
441 Attributes attributes = new LockableAttributesImpl();
442 Attribute objectClass = new LockableAttributeImpl( "objectClass" );
443 objectClass.add( "top" );
444 objectClass.add( "organizationalUnit" );
445 attributes.put( objectClass );
446
447 attributes.put( "ou", "groups" );
448 attributes.put( "creatorsName", ContextPartitionNexus.ADMIN_PRINCIPAL );
449 attributes.put( "createTimestamp", DateUtils.getGeneralizedTime() );
450
451 partitionNexus.add( "ou=groups,ou=system", new LdapName( "ou=groups,ou=system" ), attributes );
452 }
453
454
455
456
457
458 if ( !partitionNexus.hasEntry( new LdapName( "ou=configuration,ou=system" ) ) )
459 {
460 firstStart = true;
461 checkPermissionToCreateBootstrapEntries();
462
463 Attributes attributes = new LockableAttributesImpl();
464 Attribute objectClass = new LockableAttributeImpl( "objectClass" );
465 objectClass.add( "top" );
466 objectClass.add( "organizationalUnit" );
467 attributes.put( objectClass );
468
469 attributes.put( "ou", "configuration" );
470 attributes.put( "creatorsName", ContextPartitionNexus.ADMIN_PRINCIPAL );
471 attributes.put( "createTimestamp", DateUtils.getGeneralizedTime() );
472
473 partitionNexus.add( "ou=configuration,ou=system", new LdapName( "ou=configuration,ou=system" ), attributes );
474 }
475
476
477
478
479
480 if ( !partitionNexus.hasEntry( new LdapName( "ou=partitions,ou=configuration,ou=system" ) ) )
481 {
482 firstStart = true;
483 checkPermissionToCreateBootstrapEntries();
484
485 Attributes attributes = new LockableAttributesImpl();
486 Attribute objectClass = new LockableAttributeImpl( "objectClass" );
487 objectClass.add( "top" );
488 objectClass.add( "organizationalUnit" );
489 attributes.put( objectClass );
490
491 attributes.put( "ou", "partitions" );
492 attributes.put( "creatorsName", ContextPartitionNexus.ADMIN_PRINCIPAL );
493 attributes.put( "createTimestamp", DateUtils.getGeneralizedTime() );
494
495 partitionNexus.add( "ou=partitions,ou=configuration,ou=system",
496 new LdapName( "ou=partitions,ou=configuration,ou=system" ), attributes );
497 }
498
499
500
501
502
503 if ( !partitionNexus.hasEntry( new LdapName( "ou=services,ou=configuration,ou=system" ) ) )
504 {
505 firstStart = true;
506 checkPermissionToCreateBootstrapEntries();
507
508 Attributes attributes = new LockableAttributesImpl();
509 Attribute objectClass = new LockableAttributeImpl( "objectClass" );
510 objectClass.add( "top" );
511 objectClass.add( "organizationalUnit" );
512 attributes.put( objectClass );
513
514 attributes.put( "ou", "services" );
515 attributes.put( "creatorsName", ContextPartitionNexus.ADMIN_PRINCIPAL );
516 attributes.put( "createTimestamp", DateUtils.getGeneralizedTime() );
517
518 partitionNexus.add( "ou=services,ou=configuration,ou=system",
519 new LdapName( "ou=services,ou=configuration,ou=system" ), attributes );
520 }
521
522
523
524
525
526 if ( !partitionNexus.hasEntry( new LdapName( "ou=interceptors,ou=configuration,ou=system" ) ) )
527 {
528 firstStart = true;
529 checkPermissionToCreateBootstrapEntries();
530
531 Attributes attributes = new LockableAttributesImpl();
532 Attribute objectClass = new LockableAttributeImpl( "objectClass" );
533 objectClass.add( "top" );
534 objectClass.add( "organizationalUnit" );
535 attributes.put( objectClass );
536
537 attributes.put( "ou", "interceptors" );
538 attributes.put( "creatorsName", ContextPartitionNexus.ADMIN_PRINCIPAL );
539 attributes.put( "createTimestamp", DateUtils.getGeneralizedTime() );
540
541 partitionNexus.add( "ou=interceptors,ou=configuration,ou=system",
542 new LdapName( "ou=interceptors,ou=configuration,ou=system" ), attributes );
543 }
544
545
546
547
548
549 if ( !partitionNexus.hasEntry( new LdapName( "prefNodeName=sysPrefRoot,ou=system" ) ) )
550 {
551 firstStart = true;
552 checkPermissionToCreateBootstrapEntries();
553
554 Attributes attributes = new LockableAttributesImpl();
555 Attribute objectClass = new LockableAttributeImpl( "objectClass" );
556 objectClass.add( "top" );
557 objectClass.add( "organizationalUnit" );
558 attributes.put( objectClass );
559
560 attributes.put( "objectClass", "extensibleObject" );
561 attributes.put( "prefNodeName", "sysPrefRoot" );
562 attributes.put( "creatorsName", ContextPartitionNexus.ADMIN_PRINCIPAL );
563 attributes.put( "createTimestamp", DateUtils.getGeneralizedTime() );
564
565 LdapName dn = new LdapName( "prefNodeName=sysPrefRoot,ou=system" );
566
567 partitionNexus.add( "prefNodeName=sysPrefRoot,ou=system", dn, attributes );
568 }
569
570 return firstStart;
571 }
572
573 private void checkPermissionToCreateBootstrapEntries() throws NamingException
574 {
575 String principal = ( String ) environment.get( Context.SECURITY_PRINCIPAL );
576 if( principal == null || !ContextPartitionNexus.ADMIN_PRINCIPAL.equals( principal ) )
577 {
578 throw new NoPermissionException(
579 "Only '" + ContextPartitionNexus.ADMIN_PRINCIPAL + "' can initiate the first run." );
580 }
581 }
582
583
584
585 private void createTestEntries() throws NamingException
586 {
587
588
589
590
591
592
593 Iterator i = startupConfiguration.getTestEntries().iterator();
594 while( i.hasNext() )
595 {
596 Attributes entry = ( Attributes ) i.next();
597 entry.put( "creatorsName", ContextPartitionNexus.ADMIN_PRINCIPAL );
598 entry.put( "createTimestamp", DateUtils.getGeneralizedTime() );
599
600 Attribute dn = ( Attribute ) entry.get( "dn" ).clone();
601 AttributeTypeRegistry registry = globalRegistries.getAttributeTypeRegistry();
602 NameComponentNormalizer ncn = new ConcreteNameComponentNormalizer( registry );
603 DnParser parser = new DnParser( ncn );
604 Name ndn = parser.parse( ( String ) dn.get() );
605
606 partitionNexus.add( ( String ) dn.get(), ndn, entry );
607 }
608 }
609
610 /***
611 * Kicks off the initialization of the entire system.
612 *
613 * @throws javax.naming.NamingException if there are problems along the way
614 */
615 private void initialize() throws NamingException
616 {
617
618
619
620
621 BootstrapRegistries bootstrapRegistries = new BootstrapRegistries();
622
623 BootstrapSchemaLoader loader = new BootstrapSchemaLoader();
624 loader.load( startupConfiguration.getBootstrapSchemas(), bootstrapRegistries );
625
626 java.util.List errors = bootstrapRegistries.checkRefInteg();
627 if ( !errors.isEmpty() )
628 {
629 NamingException e = new NamingException();
630
631 e.setRootCause( ( Throwable ) errors.get( 0 ) );
632
633 throw e;
634 }
635
636 globalRegistries = new GlobalRegistries( bootstrapRegistries );
637
638 partitionNexus = new DefaultContextPartitionNexus( new LockableAttributesImpl() );
639 partitionNexus.init( configuration, null );
640
641 interceptorChain = new InterceptorChain();
642 interceptorChain.init( configuration );
643 }
644 }