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
20 import org.apache.ldap.common.exception.LdapNoPermissionException;
21 import org.apache.ldap.common.filter.PresenceNode;
22 import org.apache.ldap.common.message.LockableAttributesImpl;
23 import org.apache.ldap.common.name.LdapName;
24 import org.apache.ldap.common.util.NamespaceTools;
25 import org.apache.ldap.server.PartitionNexus;
26 import org.apache.ldap.server.authn.AuthenticationService;
27 import org.apache.ldap.server.authn.LdapPrincipal;
28
29 import javax.naming.*;
30 import javax.naming.directory.Attribute;
31 import javax.naming.directory.Attributes;
32 import javax.naming.directory.DirContext;
33 import javax.naming.directory.SearchControls;
34 import javax.naming.ldap.Control;
35 import javax.naming.spi.DirStateFactory;
36 import javax.naming.spi.DirectoryManager;
37 import java.io.Serializable;
38 import java.util.Hashtable;
39
40
41 /***
42 * A non-federated abstract Context implementation.
43 *
44 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
45 * @version $Rev: 159259 $
46 */
47 public abstract class ServerContext implements Context
48 {
49 /*** property key used for deleting the old RDN on a rename */
50 public static final String DELETE_OLD_RDN_PROP = "java.naming.ldap.deleteRDN";
51
52 /*** The interceptor proxy to the backend nexus */
53 private final PartitionNexus nexusProxy;
54
55 /*** The cloned environment used by this Context */
56 private final Hashtable env;
57
58 /*** The distinguished name of this Context */
59 private final LdapName dn;
60
61 /*** The Principal associated with this context */
62 private LdapPrincipal principal;
63
64
65
66
67
68
69 /***
70 * Must be called by all subclasses to initialize the nexus proxy and the
71 * environment settings to be used by this Context implementation. This
72 * specific contstructor relies on the presence of the {@link
73 * Context#PROVIDER_URL} key and value to determine the distinguished name
74 * of the newly created context. It also checks to make sure the
75 * referenced name actually exists within the system. This constructor
76 * is used for all InitialContext requests.
77 *
78 * @param nexusProxy the intercepting proxy to the nexus.
79 * @param env the environment properties used by this context.
80 * @throws NamingException if the environment parameters are not set
81 * correctly.
82 */
83 protected ServerContext( PartitionNexus nexusProxy, Hashtable env ) throws NamingException
84 {
85 String url;
86
87
88 this.nexusProxy = nexusProxy;
89
90 this.env = ( Hashtable ) env.clone();
91
92
93
94
95
96 if ( ! env.containsKey( Context.PROVIDER_URL ) )
97 {
98 String msg = "Expected property " + Context.PROVIDER_URL;
99
100 msg += " but could not find it in env!";
101
102 throw new ConfigurationException( msg );
103 }
104
105 url = ( String ) env.get( Context.PROVIDER_URL );
106
107 if ( url == null )
108 {
109 String msg = "Expected value for property " + Context.PROVIDER_URL;
110
111 msg += " but it was set to null in env!";
112
113 throw new ConfigurationException( msg );
114 }
115
116 dn = new LdapName( url );
117
118 if ( ! nexusProxy.hasEntry( dn ) )
119 {
120 throw new NameNotFoundException( dn + " does not exist" );
121 }
122 }
123
124
125 /***
126 * Must be called by all subclasses to initialize the nexus proxy and the
127 * environment settings to be used by this Context implementation. This
128 * constructor is used to propagate new contexts from existing contexts.
129 *
130 * @param principal the directory user principal that is propagated
131 * @param nexusProxy the intercepting proxy to the nexus
132 * @param env the environment properties used by this context
133 * @param dn the distinguished name of this context
134 */
135 protected ServerContext( LdapPrincipal principal, PartitionNexus nexusProxy, Hashtable env, Name dn )
136 {
137 this.dn = ( LdapName ) dn.clone();
138
139 this.env = ( Hashtable ) env.clone();
140
141 this.env.put( PROVIDER_URL, dn.toString() );
142
143 this.nexusProxy = nexusProxy;
144
145 this.principal = principal;
146 }
147
148
149
150
151
152
153
154 /***
155 * Gets the principal of the authenticated user which also happens to own
156 */
157 public LdapPrincipal getPrincipal()
158 {
159 return principal;
160 }
161
162
163 /***
164 * Sets the principal of the authenticated user which also happens to own.
165 * This method can be invoked only once to keep this property safe. This
166 * method has been changed to be public but it can only be set by the
167 * AuthenticationService to prevent malicious code from changing the
168 * effective principal.
169 */
170 public void setPrincipal( AuthenticationService.TrustedPrincipalWrapper wrapper )
171 {
172 this.principal = wrapper.getPrincipal();
173 }
174
175
176
177
178
179
180
181 /***
182 * Gets the RootNexus proxy.
183 *
184 * @return the proxy to the backend nexus.
185 */
186 protected PartitionNexus getNexusProxy()
187 {
188 return nexusProxy ;
189 }
190
191
192 /***
193 * Gets the distinguished name of the entry associated with this Context.
194 *
195 * @return the distinguished name of this Context's entry.
196 */
197 protected Name getDn()
198 {
199 return dn;
200 }
201
202
203
204
205
206
207
208 /***
209 * @see javax.naming.Context#close()
210 */
211 public void close() throws NamingException
212 {
213
214 }
215
216
217 /***
218 * @see javax.naming.Context#getNameInNamespace()
219 */
220 public String getNameInNamespace() throws NamingException
221 {
222 return dn.toString();
223 }
224
225
226 /***
227 * @see javax.naming.Context#getEnvironment()
228 */
229 public Hashtable getEnvironment()
230 {
231 return env;
232 }
233
234
235 /***
236 * @see javax.naming.Context#addToEnvironment(java.lang.String,
237 * java.lang.Object)
238 */
239 public Object addToEnvironment( String propName, Object propVal ) throws NamingException
240 {
241 return env.put( propName, propVal );
242 }
243
244
245 /***
246 * @see javax.naming.Context#removeFromEnvironment(java.lang.String)
247 */
248 public Object removeFromEnvironment( String propName ) throws NamingException
249 {
250 return env.remove( propName );
251 }
252
253
254 /***
255 * @see javax.naming.Context#createSubcontext(java.lang.String)
256 */
257 public Context createSubcontext( String name ) throws NamingException
258 {
259 return createSubcontext( new LdapName( name ) );
260 }
261
262
263 /***
264 * @see javax.naming.Context#createSubcontext(javax.naming.Name)
265 */
266 public Context createSubcontext( Name name ) throws NamingException
267 {
268 Attributes attributes = new LockableAttributesImpl();
269
270 LdapName target = buildTarget( name );
271
272 String rdn = name.get( name.size() - 1 );
273
274 String rdnAttribute = NamespaceTools.getRdnAttribute( rdn );
275
276 String rdnValue = NamespaceTools.getRdnValue( rdn );
277
278 attributes.put( rdnAttribute, rdnValue );
279
280 attributes.put( JavaLdapSupport.OBJECTCLASS_ATTR, JavaLdapSupport.JCONTAINER_ATTR );
281
282 attributes.put( JavaLdapSupport.OBJECTCLASS_ATTR, JavaLdapSupport.TOP_ATTR );
283
284
285
286
287
288
289
290
291 nexusProxy.add( target.toString(), target, attributes );
292
293 ServerLdapContext ctx = new ServerLdapContext( principal, nexusProxy, env, target );
294
295 Control [] controls = ( Control [] ) ( ( ServerLdapContext ) this ).getRequestControls().clone();
296
297 ctx.setRequestControls( controls );
298
299 return ctx;
300 }
301
302
303 /***
304 * @see javax.naming.Context#destroySubcontext(java.lang.String)
305 */
306 public void destroySubcontext( String name ) throws NamingException
307 {
308 destroySubcontext( new LdapName( name ) );
309 }
310
311
312 /***
313 * @see javax.naming.Context#destroySubcontext(javax.naming.Name)
314 */
315 public void destroySubcontext( Name name ) throws NamingException
316 {
317 Name target = buildTarget( name );
318
319 if ( target.size() == 0 )
320 {
321 throw new LdapNoPermissionException( "can't delete the rootDSE" );
322 }
323
324 nexusProxy.delete( target );
325 }
326
327
328 /***
329 * @see javax.naming.Context#bind(java.lang.String, java.lang.Object)
330 */
331 public void bind( String name, Object obj ) throws NamingException
332 {
333 bind( new LdapName( name ), obj );
334 }
335
336
337 /***
338 * @see javax.naming.Context#bind(javax.naming.Name, java.lang.Object)
339 */
340 public void bind( Name name, Object obj ) throws NamingException
341 {
342
343 DirStateFactory.Result res = DirectoryManager.getStateToBind( obj, name, this, env, null );
344
345 Attributes outAttrs = res.getAttributes();
346
347 if ( outAttrs != null )
348 {
349 Name target = buildTarget( name );
350
351 nexusProxy.add( target.toString(), target, outAttrs );
352
353 return;
354 }
355
356
357 if ( obj instanceof Referenceable )
358 {
359 obj = ( ( Referenceable ) obj ).getReference();
360
361 throw new NamingException( "Do not know how to store Referenceables yet!" );
362 }
363
364
365 if ( obj instanceof Reference )
366 {
367
368
369 throw new NamingException( "Do not know how to store References yet!" );
370 }
371 else if ( obj instanceof Serializable )
372 {
373
374
375 Attributes attributes = new LockableAttributesImpl();
376
377 if ( outAttrs != null && outAttrs.size() > 0 )
378 {
379 NamingEnumeration list = outAttrs.getAll();
380
381 while ( list.hasMore() )
382 {
383 attributes.put( ( Attribute ) list.next() );
384 }
385 }
386
387 Name target = buildTarget( name );
388
389
390
391 JavaLdapSupport.serialize( attributes, obj );
392
393 nexusProxy.add( target.toString(), target, attributes );
394 }
395 else if ( obj instanceof DirContext )
396 {
397
398
399 Attributes attributes = ( ( DirContext ) obj ).getAttributes( "" );
400
401 if ( outAttrs != null && outAttrs.size() > 0 )
402 {
403 NamingEnumeration list = outAttrs.getAll();
404
405 while ( list.hasMore() )
406 {
407 attributes.put( ( Attribute ) list.next() );
408 }
409 }
410
411 Name target = buildTarget( name );
412
413 nexusProxy.add( target.toString(), target, attributes );
414 }
415 else
416 {
417 throw new NamingException( "Can't find a way to bind: " + obj );
418 }
419 }
420
421
422 /***
423 * @see javax.naming.Context#rename(java.lang.String, java.lang.String)
424 */
425 public void rename( String oldName, String newName ) throws NamingException
426 {
427 rename( new LdapName( oldName ), new LdapName( newName ) );
428 }
429
430
431 /***
432 * @see javax.naming.Context#rename(javax.naming.Name, javax.naming.Name)
433 */
434 public void rename( Name oldName, Name newName ) throws NamingException
435 {
436 Name oldDn = buildTarget( oldName );
437
438 Name newDn = buildTarget( newName );
439
440 if ( oldDn.size() == 0 )
441 {
442 throw new LdapNoPermissionException( "can't rename the rootDSE" );
443 }
444
445 Name oldBase = oldName.getSuffix( 1 );
446
447 Name newBase = newName.getSuffix( 1 );
448
449 String newRdn = newName.get( newName.size() - 1 );
450
451 String oldRdn = oldName.get( oldName.size() - 1 );
452
453 boolean delOldRdn = true;
454
455
456
457
458
459 if ( null != env.get( DELETE_OLD_RDN_PROP ) )
460 {
461 String delOldRdnStr = ( String ) env.get( DELETE_OLD_RDN_PROP );
462
463 delOldRdn = ! delOldRdnStr.equals( "false" );
464
465 delOldRdn = delOldRdn || delOldRdnStr.equals( "no" );
466
467 delOldRdn = delOldRdn || delOldRdnStr.equals( "0" );
468 }
469
470
471
472
473
474
475
476
477
478 if ( oldName.size() == newName.size() && oldBase.equals( newBase ) )
479 {
480 nexusProxy.modifyRn( oldDn, newRdn, delOldRdn );
481 }
482 else
483 {
484 Name parent = newDn.getSuffix( 1 );
485
486 if ( newRdn.equalsIgnoreCase( oldRdn ) )
487 {
488 nexusProxy.move( oldDn, parent );
489 }
490 else
491 {
492 nexusProxy.move( oldDn, parent, newRdn, delOldRdn );
493 }
494 }
495 }
496
497
498 /***
499 * @see javax.naming.Context#rebind(java.lang.String, java.lang.Object)
500 */
501 public void rebind( String name, Object obj ) throws NamingException
502 {
503 rebind( new LdapName( name ), obj );
504 }
505
506
507 /***
508 * @see javax.naming.Context#rebind(javax.naming.Name, java.lang.Object)
509 */
510 public void rebind( Name name, Object obj ) throws NamingException
511 {
512 Name target = buildTarget( name );
513
514 if ( nexusProxy.hasEntry( target ) )
515 {
516 nexusProxy.delete( target );
517 }
518
519 bind( name, obj );
520 }
521
522
523 /***
524 * @see javax.naming.Context#unbind(java.lang.String)
525 */
526 public void unbind( String name ) throws NamingException
527 {
528 unbind( new LdapName( name ) );
529 }
530
531
532 /***
533 * @see javax.naming.Context#unbind(javax.naming.Name)
534 */
535 public void unbind( Name name ) throws NamingException
536 {
537 nexusProxy.delete( buildTarget( name ) );
538 }
539
540
541 /***
542 * @see javax.naming.Context#lookup(java.lang.String)
543 */
544 public Object lookup( String name ) throws NamingException
545 {
546 return lookup( new LdapName( name ) );
547 }
548
549
550 /***
551 * @see javax.naming.Context#lookup(javax.naming.Name)
552 */
553 public Object lookup( Name name ) throws NamingException
554 {
555 Object obj = null;
556
557 LdapName target = buildTarget( name );
558
559 Attributes attributes = nexusProxy.lookup( target );
560
561 try
562 {
563 obj = DirectoryManager.getObjectInstance( null, name, this, env, attributes );
564 }
565 catch ( Exception e )
566 {
567 throw new NamingException( e.getMessage() );
568 }
569
570 if ( obj != null )
571 {
572 return obj;
573 }
574
575
576 if ( attributes.get( JavaLdapSupport.JCLASSNAME_ATTR ) != null )
577 {
578
579 return JavaLdapSupport.deserialize( attributes );
580 }
581
582
583 ServerLdapContext ctx = new ServerLdapContext( principal, nexusProxy, env, target );
584
585
586 Control [] controls = ( ( ServerLdapContext ) this ).getRequestControls();
587
588 if ( null != controls )
589 {
590 ctx.setRequestControls( ( Control [] ) controls.clone() );
591 }
592
593 return ctx;
594 }
595
596
597 /***
598 * @see javax.naming.Context#lookupLink(java.lang.String)
599 */
600 public Object lookupLink( String name ) throws NamingException
601 {
602 throw new UnsupportedOperationException();
603 }
604
605
606 /***
607 * @see javax.naming.Context#lookupLink(javax.naming.Name)
608 */
609 public Object lookupLink( Name name ) throws NamingException
610 {
611 throw new UnsupportedOperationException();
612 }
613
614
615 /***
616 * Non-federated implementation presuming the name argument is not a
617 * composite name spanning multiple namespaces but a compound name in
618 * the same LDAP namespace. Hence the parser returned is always the
619 * same as calling this method with the empty String.
620 *
621 * @see javax.naming.Context#getNameParser(java.lang.String)
622 */
623 public NameParser getNameParser( String name ) throws NamingException
624 {
625 return LdapName.getNameParser();
626 }
627
628
629 /***
630 * Non-federated implementation presuming the name argument is not a
631 * composite name spanning multiple namespaces but a compound name in
632 * the same LDAP namespace. Hence the parser returned is always the
633 * same as calling this method with the empty String Name.
634 *
635 * @see javax.naming.Context#getNameParser(javax.naming.Name)
636 */
637 public NameParser getNameParser( Name name ) throws NamingException
638 {
639 return LdapName.getNameParser();
640 }
641
642
643 /***
644 * @see javax.naming.Context#list(java.lang.String)
645 */
646 public NamingEnumeration list( String name ) throws NamingException
647 {
648 return list( new LdapName( name ) );
649 }
650
651
652 /***
653 * @see javax.naming.Context#list(javax.naming.Name)
654 */
655 public NamingEnumeration list( Name name ) throws NamingException
656 {
657 return nexusProxy.list( buildTarget( name ) );
658 }
659
660
661 /***
662 * @see javax.naming.Context#listBindings(java.lang.String)
663 */
664 public NamingEnumeration listBindings( String name ) throws NamingException
665 {
666 return listBindings( new LdapName( name ) );
667 }
668
669
670 /***
671 * @see javax.naming.Context#listBindings(javax.naming.Name)
672 */
673 public NamingEnumeration listBindings( Name name ) throws NamingException
674 {
675
676 Name base = buildTarget( name );
677
678 PresenceNode filter = new PresenceNode( "objectClass" );
679
680 SearchControls ctls = new SearchControls();
681
682 ctls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
683
684 return nexusProxy.search( base , getEnvironment(), filter, ctls );
685 }
686
687
688 /***
689 * @see javax.naming.Context#composeName(java.lang.String, java.lang.String)
690 */
691 public String composeName( String name, String prefix ) throws NamingException
692 {
693 return composeName( new LdapName( name ), new LdapName( prefix ) ).toString();
694 }
695
696
697 /***
698 * @see javax.naming.Context#composeName(javax.naming.Name,
699 * javax.naming.Name)
700 */
701 public Name composeName( Name name, Name prefix ) throws NamingException
702 {
703
704 if ( prefix == null || prefix.size() == 0 )
705 {
706 return name;
707 }
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725 Name fqn = buildTarget( name );
726
727 String head = prefix.get( 0 );
728
729
730 while ( fqn.size() > 0 )
731 {
732
733 if ( fqn.get( 0 ).equalsIgnoreCase( head ) )
734 {
735 return fqn;
736 }
737 else
738 {
739 fqn.remove( 0 );
740 }
741 }
742
743 String msg = "The prefix '" + prefix + "' is not an ancestor of this ";
744
745 msg += "entry '" + dn + "'";
746
747 throw new NamingException( msg );
748 }
749
750
751
752
753
754
755
756 /***
757 * Clones this context's DN and adds the components of the name relative to
758 * this context to the left hand side of this context's cloned DN.
759 *
760 * @param relativeName a name relative to this context.
761 * @return the name of the target
762 * @throws InvalidNameException if relativeName is not a valid name in
763 * the LDAP namespace.
764 */
765 LdapName buildTarget( Name relativeName ) throws InvalidNameException
766 {
767
768 LdapName target = ( LdapName ) dn.clone();
769
770
771 target.addAll( target.size(), relativeName );
772
773 return target;
774 }
775 }