/**
   * Search for the user's entry. Determine the distinguished name of the user's entry and
   * optionally an authorization identity for the user.
   *
   * @param ctx an LDAP context to use for the search
   * @return the user's distinguished name or an empty string if none was found.
   * @exception LoginException if the user's entry cannot be found.
   */
  private String findUserDN(LdapContext ctx) throws LoginException {

    String userDN = "";

    // Locate the user's LDAP entry
    if (userFilter != null) {
      if (debug) {
        System.out.println(
            "\t\t[LdapLoginModule] " + "searching for entry belonging to user: "******"\t\t[LdapLoginModule] " + "cannot search for entry belonging to user: "******"Cannot find user's LDAP entry");
    }

    try {
      NamingEnumeration results =
          ctx.search("", replaceUsernameToken(filterMatcher, userFilter), constraints);

      // Extract the distinguished name of the user's entry
      // (Use the first entry if more than one is returned)
      if (results.hasMore()) {
        SearchResult entry = (SearchResult) results.next();

        // %%% - use the SearchResult.getNameInNamespace method
        //        available in JDK 1.5 and later.
        //        (can remove call to constraints.setReturningObjFlag)
        userDN = ((Context) entry.getObject()).getNameInNamespace();

        if (debug) {
          System.out.println("\t\t[LdapLoginModule] found entry: " + userDN);
        }

        // Extract a value from user's authorization identity attribute
        if (authzIdentityAttr != null) {
          Attribute attr = entry.getAttributes().get(authzIdentityAttr);
          if (attr != null) {
            Object val = attr.get();
            if (val instanceof String) {
              authzIdentity = (String) val;
            }
          }
        }

        results.close();

      } else {
        // Bad username
        if (debug) {
          System.out.println("\t\t[LdapLoginModule] user's entry " + "not found");
        }
      }

    } catch (NamingException e) {
      // ignore
    }

    if (userDN.equals("")) {
      throw (LoginException) new FailedLoginException("Cannot find user's LDAP entry");
    } else {
      return userDN;
    }
  }
  protected NameClassPair createItem(String dn, Attributes attrs, Vector respCtls)
      throws NamingException {

    Object obj = null;

    String relStart; // name relative to starting search context
    String relHome; // name relative to homeCtx.currentDN
    boolean relative = true; // whether relative to currentDN

    // need to strip off all but lowest component of dn
    // so that is relative to current context (currentDN)

    try {
      Name parsed = new LdapName(dn);
      // System.err.println("dn string: " + dn);
      // System.err.println("dn name: " + parsed);

      if (startName != null && parsed.startsWith(startName)) {
        relStart = parsed.getSuffix(startName.size()).toString();
        relHome = parsed.getSuffix(homeCtx.currentParsedDN.size()).toString();
      } else {
        relative = false;
        relHome =
            relStart =
                LdapURL.toUrlString(
                    homeCtx.hostname, homeCtx.port_number, dn, homeCtx.hasLdapsScheme);
      }
    } catch (NamingException e) {
      // could not parse name
      relative = false;
      relHome =
          relStart =
              LdapURL.toUrlString(
                  homeCtx.hostname, homeCtx.port_number, dn, homeCtx.hasLdapsScheme);
    }

    // Name relative to search context
    CompositeName cn = new CompositeName();
    if (!relStart.equals("")) {
      cn.add(relStart);
    }

    // Name relative to homeCtx
    CompositeName rcn = new CompositeName();
    if (!relHome.equals("")) {
      rcn.add(relHome);
    }
    // System.err.println("relStart: " + cn);
    // System.err.println("relHome: " + rcn);

    // Fix attributes to be able to get schema
    homeCtx.setParents(attrs, rcn);

    // only generate object when requested
    if (searchArgs.cons.getReturningObjFlag()) {

      if (attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME]) != null) {
        // Entry contains Java-object attributes (ser/ref object)
        // serialized object or object reference
        obj = Obj.decodeObject(attrs);
      }
      if (obj == null) {
        obj = new LdapCtx(homeCtx, dn);
      }

      // Call getObjectInstance before removing unrequested attributes
      try {
        // rcn is either relative to homeCtx or a fully qualified DN
        obj =
            DirectoryManager.getObjectInstance(
                obj, rcn, (relative ? homeCtx : null), homeCtx.envprops, attrs);
      } catch (NamingException e) {
        throw e;
      } catch (Exception e) {
        NamingException ne = new NamingException("problem generating object using object factory");
        ne.setRootCause(e);
        throw ne;
      }

      // remove Java attributes from result, if necessary
      // Even if CLASSNAME attr not there, there might be some
      // residual attributes

      String[] reqAttrs;
      if ((reqAttrs = searchArgs.reqAttrs) != null) {
        // create an attribute set for those requested
        Attributes rattrs = new BasicAttributes(true); // caseignore
        for (int i = 0; i < reqAttrs.length; i++) {
          rattrs.put(reqAttrs[i], null);
        }
        for (int i = 0; i < Obj.JAVA_ATTRIBUTES.length; i++) {
          // Remove Java-object attributes if not requested
          if (rattrs.get(Obj.JAVA_ATTRIBUTES[i]) == null) {
            attrs.remove(Obj.JAVA_ATTRIBUTES[i]);
          }
        }
      }
    }

    /*
     * name in search result is either the stringified composite name
     * relative to the search context that can be passed directly to
     * methods of the search context, or the fully qualified DN
     * which can be used with the initial context.
     */
    SearchResult sr;
    if (respCtls != null) {
      sr =
          new SearchResultWithControls(
              (relative ? cn.toString() : relStart),
              obj,
              attrs,
              relative,
              homeCtx.convertControls(respCtls));
    } else {
      sr = new SearchResult((relative ? cn.toString() : relStart), obj, attrs, relative);
    }
    sr.setNameInNamespace(dn);
    return sr;
  }