1 /*
   2  * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jndi.url.ldap;
  27 
  28 import javax.naming.spi.ResolveResult;
  29 import javax.naming.*;
  30 import javax.naming.directory.*;
  31 import java.util.Hashtable;
  32 import java.util.StringTokenizer;
  33 import com.sun.jndi.ldap.LdapURL;
  34 
  35 /**
  36  * An LDAP URL context.
  37  *
  38  * @author Rosanna Lee
  39  * @author Scott Seligman
  40  */
  41 
  42 final public class ldapURLContext
  43         extends com.sun.jndi.toolkit.url.GenericURLDirContext {
  44 
  45     ldapURLContext(Hashtable env) {
  46         super(env);
  47     }
  48 
  49     /**
  50       * Resolves 'name' into a target context with remaining name.
  51       * It only resolves the hostname/port number. The remaining name
  52       * contains the root DN.
  53       *
  54       * For example, with a LDAP URL "ldap://localhost:389/o=widget,c=us",
  55       * this method resolves "ldap://localhost:389/" to the root LDAP
  56       * context on the server 'localhost' on port 389,
  57       * and returns as the remaining name "o=widget, c=us".
  58       */
  59     protected ResolveResult getRootURLContext(String name, Hashtable env)
  60     throws NamingException {
  61         return ldapURLContextFactory.getUsingURLIgnoreRootDN(name, env);
  62     }
  63 
  64     /**
  65      * Return the suffix of an ldap url.
  66      * prefix parameter is ignored.
  67      */
  68     protected Name getURLSuffix(String prefix, String url)
  69         throws NamingException {
  70 
  71         LdapURL ldapUrl = new LdapURL(url);
  72         String dn = (ldapUrl.getDN() != null? ldapUrl.getDN() : "");
  73 
  74         // Represent DN as empty or single-component composite name.
  75         CompositeName remaining = new CompositeName();
  76         if (!"".equals(dn)) {
  77             // if nonempty, add component
  78             remaining.add(dn);
  79         }
  80         return remaining;
  81     }
  82 
  83     /*
  84      * Override context operations.
  85      * Test for presence of LDAP URL query components in the name argument.
  86      * Query components are permitted only for search operations and only
  87      * when the name has a single component.
  88      */
  89 
  90     public Object lookup(String name) throws NamingException {
  91         if (LdapURL.hasQueryComponents(name)) {
  92             throw new InvalidNameException(name);
  93         } else {
  94             return super.lookup(name);
  95         }
  96     }
  97 
  98     public Object lookup(Name name) throws NamingException {
  99         if (LdapURL.hasQueryComponents(name.get(0))) {
 100             throw new InvalidNameException(name.toString());
 101         } else {
 102             return super.lookup(name);
 103         }
 104     }
 105 
 106     public void bind(String name, Object obj) throws NamingException {
 107         if (LdapURL.hasQueryComponents(name)) {
 108             throw new InvalidNameException(name);
 109         } else {
 110             super.bind(name, obj);
 111         }
 112     }
 113 
 114     public void bind(Name name, Object obj) throws NamingException {
 115         if (LdapURL.hasQueryComponents(name.get(0))) {
 116             throw new InvalidNameException(name.toString());
 117         } else {
 118             super.bind(name, obj);
 119         }
 120     }
 121 
 122     public void rebind(String name, Object obj) throws NamingException {
 123         if (LdapURL.hasQueryComponents(name)) {
 124             throw new InvalidNameException(name);
 125         } else {
 126             super.rebind(name, obj);
 127         }
 128     }
 129 
 130     public void rebind(Name name, Object obj) throws NamingException {
 131         if (LdapURL.hasQueryComponents(name.get(0))) {
 132             throw new InvalidNameException(name.toString());
 133         } else {
 134             super.rebind(name, obj);
 135         }
 136     }
 137 
 138     public void unbind(String name) throws NamingException {
 139         if (LdapURL.hasQueryComponents(name)) {
 140             throw new InvalidNameException(name);
 141         } else {
 142             super.unbind(name);
 143         }
 144     }
 145 
 146     public void unbind(Name name) throws NamingException {
 147         if (LdapURL.hasQueryComponents(name.get(0))) {
 148             throw new InvalidNameException(name.toString());
 149         } else {
 150             super.unbind(name);
 151         }
 152     }
 153 
 154     public void rename(String oldName, String newName) throws NamingException {
 155         if (LdapURL.hasQueryComponents(oldName)) {
 156             throw new InvalidNameException(oldName);
 157         } else if (LdapURL.hasQueryComponents(newName)) {
 158             throw new InvalidNameException(newName);
 159         } else {
 160             super.rename(oldName, newName);
 161         }
 162     }
 163 
 164     public void rename(Name oldName, Name newName) throws NamingException {
 165         if (LdapURL.hasQueryComponents(oldName.get(0))) {
 166             throw new InvalidNameException(oldName.toString());
 167         } else if (LdapURL.hasQueryComponents(newName.get(0))) {
 168             throw new InvalidNameException(newName.toString());
 169         } else {
 170             super.rename(oldName, newName);
 171         }
 172     }
 173 
 174     public NamingEnumeration list(String name)  throws NamingException {
 175         if (LdapURL.hasQueryComponents(name)) {
 176             throw new InvalidNameException(name);
 177         } else {
 178             return super.list(name);
 179         }
 180     }
 181 
 182     public NamingEnumeration list(Name name) throws NamingException {
 183         if (LdapURL.hasQueryComponents(name.get(0))) {
 184             throw new InvalidNameException(name.toString());
 185         } else {
 186             return super.list(name);
 187         }
 188     }
 189 
 190     public NamingEnumeration listBindings(String name) throws NamingException {
 191         if (LdapURL.hasQueryComponents(name)) {
 192             throw new InvalidNameException(name);
 193         } else {
 194             return super.listBindings(name);
 195         }
 196     }
 197 
 198     public NamingEnumeration listBindings(Name name) throws NamingException {
 199         if (LdapURL.hasQueryComponents(name.get(0))) {
 200             throw new InvalidNameException(name.toString());
 201         } else {
 202             return super.listBindings(name);
 203         }
 204     }
 205 
 206     public void destroySubcontext(String name) throws NamingException {
 207         if (LdapURL.hasQueryComponents(name)) {
 208             throw new InvalidNameException(name);
 209         } else {
 210             super.destroySubcontext(name);
 211         }
 212     }
 213 
 214     public void destroySubcontext(Name name) throws NamingException {
 215         if (LdapURL.hasQueryComponents(name.get(0))) {
 216             throw new InvalidNameException(name.toString());
 217         } else {
 218             super.destroySubcontext(name);
 219         }
 220     }
 221 
 222     public Context createSubcontext(String name) throws NamingException {
 223         if (LdapURL.hasQueryComponents(name)) {
 224             throw new InvalidNameException(name);
 225         } else {
 226             return super.createSubcontext(name);
 227         }
 228     }
 229 
 230     public Context createSubcontext(Name name) throws NamingException {
 231         if (LdapURL.hasQueryComponents(name.get(0))) {
 232             throw new InvalidNameException(name.toString());
 233         } else {
 234             return super.createSubcontext(name);
 235         }
 236     }
 237 
 238     public Object lookupLink(String name) throws NamingException {
 239         if (LdapURL.hasQueryComponents(name)) {
 240             throw new InvalidNameException(name);
 241         } else {
 242             return super.lookupLink(name);
 243         }
 244     }
 245 
 246     public Object lookupLink(Name name) throws NamingException {
 247         if (LdapURL.hasQueryComponents(name.get(0))) {
 248             throw new InvalidNameException(name.toString());
 249         } else {
 250             return super.lookupLink(name);
 251         }
 252     }
 253 
 254     public NameParser getNameParser(String name) throws NamingException {
 255         if (LdapURL.hasQueryComponents(name)) {
 256             throw new InvalidNameException(name);
 257         } else {
 258             return super.getNameParser(name);
 259         }
 260     }
 261 
 262     public NameParser getNameParser(Name name) throws NamingException {
 263         if (LdapURL.hasQueryComponents(name.get(0))) {
 264             throw new InvalidNameException(name.toString());
 265         } else {
 266             return super.getNameParser(name);
 267         }
 268     }
 269 
 270     public String composeName(String name, String prefix)
 271         throws NamingException {
 272         if (LdapURL.hasQueryComponents(name)) {
 273             throw new InvalidNameException(name);
 274         } else if (LdapURL.hasQueryComponents(prefix)) {
 275             throw new InvalidNameException(prefix);
 276         } else {
 277             return super.composeName(name, prefix);
 278         }
 279     }
 280 
 281     public Name composeName(Name name, Name prefix) throws NamingException {
 282         if (LdapURL.hasQueryComponents(name.get(0))) {
 283             throw new InvalidNameException(name.toString());
 284         } else if (LdapURL.hasQueryComponents(prefix.get(0))) {
 285             throw new InvalidNameException(prefix.toString());
 286         } else {
 287             return super.composeName(name, prefix);
 288         }
 289     }
 290 
 291     public Attributes getAttributes(String name) throws NamingException {
 292         if (LdapURL.hasQueryComponents(name)) {
 293             throw new InvalidNameException(name);
 294         } else {
 295             return super.getAttributes(name);
 296         }
 297     }
 298 
 299     public Attributes getAttributes(Name name) throws NamingException  {
 300         if (LdapURL.hasQueryComponents(name.get(0))) {
 301             throw new InvalidNameException(name.toString());
 302         } else {
 303             return super.getAttributes(name);
 304         }
 305     }
 306 
 307     public Attributes getAttributes(String name, String[] attrIds)
 308         throws NamingException {
 309         if (LdapURL.hasQueryComponents(name)) {
 310             throw new InvalidNameException(name);
 311         } else {
 312             return super.getAttributes(name, attrIds);
 313         }
 314     }
 315 
 316     public Attributes getAttributes(Name name, String[] attrIds)
 317         throws NamingException {
 318         if (LdapURL.hasQueryComponents(name.get(0))) {
 319             throw new InvalidNameException(name.toString());
 320         } else {
 321             return super.getAttributes(name, attrIds);
 322         }
 323     }
 324 
 325     public void modifyAttributes(String name, int mod_op, Attributes attrs)
 326         throws NamingException {
 327         if (LdapURL.hasQueryComponents(name)) {
 328             throw new InvalidNameException(name);
 329         } else {
 330             super.modifyAttributes(name, mod_op, attrs);
 331         }
 332     }
 333 
 334     public void modifyAttributes(Name name, int mod_op, Attributes attrs)
 335         throws NamingException {
 336         if (LdapURL.hasQueryComponents(name.get(0))) {
 337             throw new InvalidNameException(name.toString());
 338         } else {
 339             super.modifyAttributes(name, mod_op, attrs);
 340         }
 341     }
 342 
 343     public void modifyAttributes(String name, ModificationItem[] mods)
 344         throws NamingException {
 345         if (LdapURL.hasQueryComponents(name)) {
 346             throw new InvalidNameException(name);
 347         } else {
 348             super.modifyAttributes(name, mods);
 349         }
 350     }
 351 
 352     public void modifyAttributes(Name name, ModificationItem[] mods)
 353         throws NamingException  {
 354         if (LdapURL.hasQueryComponents(name.get(0))) {
 355             throw new InvalidNameException(name.toString());
 356         } else {
 357             super.modifyAttributes(name, mods);
 358         }
 359     }
 360 
 361     public void bind(String name, Object obj, Attributes attrs)
 362         throws NamingException {
 363         if (LdapURL.hasQueryComponents(name)) {
 364             throw new InvalidNameException(name);
 365         } else {
 366             super.bind(name, obj, attrs);
 367         }
 368     }
 369 
 370     public void bind(Name name, Object obj, Attributes attrs)
 371         throws NamingException {
 372         if (LdapURL.hasQueryComponents(name.get(0))) {
 373             throw new InvalidNameException(name.toString());
 374         } else {
 375             super.bind(name, obj, attrs);
 376         }
 377     }
 378 
 379     public void rebind(String name, Object obj, Attributes attrs)
 380         throws NamingException {
 381         if (LdapURL.hasQueryComponents(name)) {
 382             throw new InvalidNameException(name);
 383         } else {
 384             super.rebind(name, obj, attrs);
 385         }
 386     }
 387 
 388     public void rebind(Name name, Object obj, Attributes attrs)
 389         throws NamingException {
 390         if (LdapURL.hasQueryComponents(name.get(0))) {
 391             throw new InvalidNameException(name.toString());
 392         } else {
 393             super.rebind(name, obj, attrs);
 394         }
 395     }
 396 
 397     public DirContext createSubcontext(String name, Attributes attrs)
 398         throws NamingException {
 399         if (LdapURL.hasQueryComponents(name)) {
 400             throw new InvalidNameException(name);
 401         } else {
 402             return super.createSubcontext(name, attrs);
 403         }
 404     }
 405 
 406     public DirContext createSubcontext(Name name, Attributes attrs)
 407         throws NamingException {
 408         if (LdapURL.hasQueryComponents(name.get(0))) {
 409             throw new InvalidNameException(name.toString());
 410         } else {
 411             return super.createSubcontext(name, attrs);
 412         }
 413     }
 414 
 415     public DirContext getSchema(String name) throws NamingException {
 416         if (LdapURL.hasQueryComponents(name)) {
 417             throw new InvalidNameException(name);
 418         } else {
 419             return super.getSchema(name);
 420         }
 421     }
 422 
 423     public DirContext getSchema(Name name) throws NamingException {
 424         if (LdapURL.hasQueryComponents(name.get(0))) {
 425             throw new InvalidNameException(name.toString());
 426         } else {
 427             return super.getSchema(name);
 428         }
 429     }
 430 
 431     public DirContext getSchemaClassDefinition(String name)
 432         throws NamingException {
 433         if (LdapURL.hasQueryComponents(name)) {
 434             throw new InvalidNameException(name);
 435         } else {
 436             return super.getSchemaClassDefinition(name);
 437         }
 438     }
 439 
 440     public DirContext getSchemaClassDefinition(Name name)
 441         throws NamingException {
 442         if (LdapURL.hasQueryComponents(name.get(0))) {
 443             throw new InvalidNameException(name.toString());
 444         } else {
 445             return super.getSchemaClassDefinition(name);
 446         }
 447     }
 448 
 449     // divert the search operation when the LDAP URL has query components
 450     public NamingEnumeration search(String name,
 451         Attributes matchingAttributes)
 452         throws NamingException {
 453 
 454         if (LdapURL.hasQueryComponents(name)) {
 455             return searchUsingURL(name);
 456         } else {
 457             return super.search(name, matchingAttributes);
 458         }
 459     }
 460 
 461     // divert the search operation when name has a single component
 462     public NamingEnumeration search(Name name,
 463         Attributes matchingAttributes)
 464         throws NamingException {
 465         if (name.size() == 1) {
 466             return search(name.get(0), matchingAttributes);
 467         } else if (LdapURL.hasQueryComponents(name.get(0))) {
 468             throw new InvalidNameException(name.toString());
 469         } else {
 470             return super.search(name, matchingAttributes);
 471         }
 472     }
 473 
 474     // divert the search operation when the LDAP URL has query components
 475     public NamingEnumeration search(String name,
 476         Attributes matchingAttributes,
 477         String[] attributesToReturn)
 478         throws NamingException {
 479 
 480         if (LdapURL.hasQueryComponents(name)) {
 481             return searchUsingURL(name);
 482         } else {
 483             return super.search(name, matchingAttributes, attributesToReturn);
 484         }
 485     }
 486 
 487     // divert the search operation when name has a single component
 488     public NamingEnumeration search(Name name,
 489         Attributes matchingAttributes,
 490         String[] attributesToReturn)
 491         throws NamingException {
 492 
 493         if (name.size() == 1) {
 494             return search(name.get(0), matchingAttributes, attributesToReturn);
 495         } else if (LdapURL.hasQueryComponents(name.get(0))) {
 496             throw new InvalidNameException(name.toString());
 497         } else {
 498             return super.search(name, matchingAttributes, attributesToReturn);
 499         }
 500     }
 501 
 502     // divert the search operation when the LDAP URL has query components
 503     public NamingEnumeration search(String name,
 504         String filter,
 505         SearchControls cons)
 506         throws NamingException {
 507 
 508         if (LdapURL.hasQueryComponents(name)) {
 509             return searchUsingURL(name);
 510         } else {
 511             return super.search(name, filter, cons);
 512         }
 513     }
 514 
 515     // divert the search operation when name has a single component
 516     public NamingEnumeration search(Name name,
 517         String filter,
 518         SearchControls cons)
 519         throws NamingException {
 520 
 521         if (name.size() == 1) {
 522             return search(name.get(0), filter, cons);
 523         } else if (LdapURL.hasQueryComponents(name.get(0))) {
 524             throw new InvalidNameException(name.toString());
 525         } else {
 526             return super.search(name, filter, cons);
 527         }
 528     }
 529 
 530     // divert the search operation when the LDAP URL has query components
 531     public NamingEnumeration search(String name,
 532         String filterExpr,
 533         Object[] filterArgs,
 534         SearchControls cons)
 535         throws NamingException {
 536 
 537         if (LdapURL.hasQueryComponents(name)) {
 538             return searchUsingURL(name);
 539         } else {
 540             return super.search(name, filterExpr, filterArgs, cons);
 541         }
 542     }
 543 
 544     // divert the search operation when name has a single component
 545     public NamingEnumeration search(Name name,
 546         String filterExpr,
 547         Object[] filterArgs,
 548         SearchControls cons)
 549         throws NamingException {
 550 
 551         if (name.size() == 1) {
 552             return search(name.get(0), filterExpr, filterArgs, cons);
 553         } else if (LdapURL.hasQueryComponents(name.get(0))) {
 554             throw new InvalidNameException(name.toString());
 555         } else {
 556             return super.search(name, filterExpr, filterArgs, cons);
 557         }
 558     }
 559 
 560     // Search using the LDAP URL in name.
 561     // LDAP URL query components override the search argments.
 562     private NamingEnumeration searchUsingURL(String name)
 563         throws NamingException {
 564 
 565         LdapURL url = new LdapURL(name);
 566 
 567         ResolveResult res = getRootURLContext(name, myEnv);
 568         DirContext ctx = (DirContext)res.getResolvedObj();
 569         try {
 570             return ctx.search(res.getRemainingName(),
 571                               setFilterUsingURL(url),
 572                               setSearchControlsUsingURL(url));
 573         } finally {
 574             ctx.close();
 575         }
 576     }
 577 
 578     /*
 579      * Initialize a String filter using the LDAP URL filter component.
 580      * If filter is not present in the URL it is initialized to its default
 581      * value as specified in RFC-2255.
 582      */
 583     private static String setFilterUsingURL(LdapURL url) {
 584 
 585         String filter = url.getFilter();
 586 
 587         if (filter == null) {
 588             filter = "(objectClass=*)"; //default value
 589         }
 590         return filter;
 591     }
 592 
 593     /*
 594      * Initialize a SearchControls object using LDAP URL query components.
 595      * Components not present in the URL are initialized to their default
 596      * values as specified in RFC-2255.
 597      */
 598     private static SearchControls setSearchControlsUsingURL(LdapURL url) {
 599 
 600         SearchControls cons = new SearchControls();
 601         String scope = url.getScope();
 602         String attributes = url.getAttributes();
 603 
 604         if (scope == null) {
 605             cons.setSearchScope(SearchControls.OBJECT_SCOPE); //default value
 606         } else {
 607             if (scope.equals("sub")) {
 608                 cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
 609             } else if (scope.equals("one")) {
 610                 cons.setSearchScope(SearchControls.ONELEVEL_SCOPE);
 611             } else if (scope.equals("base")) {
 612                 cons.setSearchScope(SearchControls.OBJECT_SCOPE);
 613             }
 614         }
 615 
 616         if (attributes == null) {
 617             cons.setReturningAttributes(null); //default value
 618         } else {
 619             StringTokenizer tokens = new StringTokenizer(attributes, ",");
 620             int count = tokens.countTokens();
 621             String[] attrs = new String[count];
 622             for (int i = 0; i < count; i ++) {
 623                 attrs[i] = tokens.nextToken();
 624             }
 625             cons.setReturningAttributes(attrs);
 626         }
 627         return cons;
 628     }
 629 }