private static void updateAdminConnectorConfiguration(
      ServerDescriptor desc, InitialLdapContext ctx, TopologyCacheFilter cacheFilter)
      throws NamingException {
    SearchControls ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    ctls.setReturningAttributes(new String[] {"ds-cfg-listen-port", "objectclass"});
    String filter = "(objectclass=ds-cfg-administration-connector)";

    LdapName jndiName = new LdapName("cn=config");
    NamingEnumeration<SearchResult> listeners = ctx.search(jndiName, filter, ctls);

    try {
      Integer adminConnectorPort = null;

      // we should have a single administration connector
      while (listeners.hasMore()) {
        SearchResult sr = listeners.next();
        String port = getFirstValue(sr, "ds-cfg-listen-port");
        adminConnectorPort = new Integer(port);
      }

      // Even if we have a single port, use an array to be consistent with
      // other protocols.
      ArrayList<Integer> adminPorts = new ArrayList<Integer>();
      ArrayList<Boolean> adminEnabled = new ArrayList<Boolean>();
      if (adminConnectorPort != null) {
        adminPorts.add(adminConnectorPort);
        adminEnabled.add(Boolean.TRUE);
      }
      desc.serverProperties.put(ServerProperty.ADMIN_PORT, adminPorts);
      desc.serverProperties.put(ServerProperty.ADMIN_ENABLED, adminEnabled);
    } finally {
      listeners.close();
    }
  }
  private static void updateLdapConfiguration(
      ServerDescriptor desc, InitialLdapContext ctx, TopologyCacheFilter cacheFilter)
      throws NamingException {
    SearchControls ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    ctls.setReturningAttributes(
        new String[] {
          "ds-cfg-enabled",
          "ds-cfg-listen-address",
          "ds-cfg-listen-port",
          "ds-cfg-use-ssl",
          "ds-cfg-allow-start-tls",
          "objectclass"
        });
    String filter = "(objectclass=ds-cfg-ldap-connection-handler)";

    LdapName jndiName = new LdapName("cn=config");
    NamingEnumeration<SearchResult> listeners = ctx.search(jndiName, filter, ctls);

    try {
      ArrayList<Integer> ldapPorts = new ArrayList<Integer>();
      ArrayList<Integer> ldapsPorts = new ArrayList<Integer>();
      ArrayList<Boolean> ldapEnabled = new ArrayList<Boolean>();
      ArrayList<Boolean> ldapsEnabled = new ArrayList<Boolean>();
      ArrayList<Boolean> startTLSEnabled = new ArrayList<Boolean>();

      desc.serverProperties.put(ServerProperty.LDAP_PORT, ldapPorts);
      desc.serverProperties.put(ServerProperty.LDAPS_PORT, ldapsPorts);
      desc.serverProperties.put(ServerProperty.LDAP_ENABLED, ldapEnabled);
      desc.serverProperties.put(ServerProperty.LDAPS_ENABLED, ldapsEnabled);
      desc.serverProperties.put(ServerProperty.STARTTLS_ENABLED, startTLSEnabled);

      while (listeners.hasMore()) {
        SearchResult sr = listeners.next();

        String port = getFirstValue(sr, "ds-cfg-listen-port");

        boolean isSecure = "true".equalsIgnoreCase(getFirstValue(sr, "ds-cfg-use-ssl"));

        boolean enabled = "true".equalsIgnoreCase(getFirstValue(sr, "ds-cfg-enabled"));
        if (isSecure) {
          ldapsPorts.add(new Integer(port));
          ldapsEnabled.add(enabled);
        } else {
          ldapPorts.add(new Integer(port));
          ldapEnabled.add(enabled);
          enabled = "true".equalsIgnoreCase(getFirstValue(sr, "ds-cfg-allow-start-tls"));
          startTLSEnabled.add(enabled);
        }
      }
    } finally {
      listeners.close();
    }
  }
 /**
  * Updates the instance key public-key certificate value of this context from the local truststore
  * of the instance bound by this context. Any current value of the certificate is overwritten. The
  * intent of this method is to retrieve the instance-key public-key certificate when this context
  * is bound to an instance, and cache it for later use in registering the instance into ADS.
  *
  * @param desc The map to update with the instance key-pair public-key certificate.
  * @param ctx The bound server instance.
  * @throws NamingException if unable to retrieve certificate from bound instance.
  */
 private static void updatePublicKeyCertificate(
     ServerDescriptor desc, InitialLdapContext ctx, TopologyCacheFilter filter)
     throws NamingException {
   /* TODO: this DN is declared in some core constants file. Create a constants
   file for the installer and import it into the core. */
   final String dnStr = "ds-cfg-key-id=ads-certificate,cn=ads-truststore";
   final LdapName dn = new LdapName(dnStr);
   for (int i = 0; i < 2; ++i) {
     /* If the entry does not exist in the instance's truststore backend, add
     it (which induces the CryptoManager to create the public-key
     certificate attribute), then repeat the search. */
     try {
       final SearchControls searchControls = new SearchControls();
       searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
       final String attrIDs[] = {"ds-cfg-public-key-certificate;binary"};
       searchControls.setReturningAttributes(attrIDs);
       final SearchResult certEntry =
           ctx.search(dn, "(objectclass=ds-cfg-instance-key)", searchControls).next();
       final Attribute certAttr = certEntry.getAttributes().get(attrIDs[0]);
       if (null != certAttr) {
         /* attribute ds-cfg-public-key-certificate is a MUST in the schema */
         desc.serverProperties.put(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE, certAttr.get());
       }
       break;
     } catch (NameNotFoundException x) {
       if (0 == i) {
         /* Poke CryptoManager to initialize truststore. Note the special
         attribute in the request. */
         final Attributes attrs = new BasicAttributes();
         final Attribute oc = new BasicAttribute("objectclass");
         oc.add("top");
         oc.add("ds-cfg-self-signed-cert-request");
         attrs.put(oc);
         ctx.createSubcontext(dn, attrs).close();
       } else {
         throw x;
       }
     }
   }
 }
  /**
   * Returns the values of the ds-base-dn-entry count attributes for the given backend monitor entry
   * using the provided InitialLdapContext.
   *
   * @param ctx the InitialLdapContext to use to update the configuration.
   * @param backendID the id of the backend.
   * @return the values of the ds-base-dn-entry count attribute.
   * @throws NamingException if there was an error.
   */
  private static Set<String> getBaseDNEntryCount(InitialLdapContext ctx, String backendID)
      throws NamingException {
    LinkedHashSet<String> v = new LinkedHashSet<String>();
    SearchControls ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
    ctls.setReturningAttributes(new String[] {"ds-base-dn-entry-count"});
    String filter = "(ds-backend-id=" + backendID + ")";

    LdapName jndiName = new LdapName("cn=monitor");
    NamingEnumeration<SearchResult> listeners = ctx.search(jndiName, filter, ctls);

    try {
      while (listeners.hasMore()) {
        SearchResult sr = listeners.next();

        v.addAll(getValues(sr, "ds-base-dn-entry-count"));
      }
    } finally {
      listeners.close();
    }
    return v;
  }
  private static void updateMiscellaneous(
      ServerDescriptor desc, InitialLdapContext ctx, TopologyCacheFilter cacheFilter)
      throws NamingException {
    SearchControls ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
    ctls.setReturningAttributes(new String[] {"ds-sync-generation-id"});
    String filter = "(|(objectclass=*)(objectclass=ldapsubentry))";

    LdapName jndiName = new LdapName("cn=schema");
    NamingEnumeration<SearchResult> listeners = ctx.search(jndiName, filter, ctls);

    try {
      while (listeners.hasMore()) {
        SearchResult sr = listeners.next();

        desc.serverProperties.put(
            ServerProperty.SCHEMA_GENERATION_ID, getFirstValue(sr, "ds-sync-generation-id"));
      }
    } finally {
      listeners.close();
    }
  }
 /**
  * Cleans up the contents of the ads truststore.
  *
  * @param ctx the bound instance.
  * @throws NamingException in case an error occurs while updating the instance's ads-truststore
  *     via LDAP.
  */
 public static void cleanAdsTrustStore(InitialLdapContext ctx) throws NamingException {
   try {
     SearchControls sc = new SearchControls();
     sc.setSearchScope(SearchControls.ONELEVEL_SCOPE);
     sc.setReturningAttributes(new String[] {SchemaConstants.NO_ATTRIBUTES});
     NamingEnumeration<SearchResult> ne =
         ctx.search(TRUSTSTORE_DN, "(objectclass=ds-cfg-instance-key)", sc);
     ArrayList<String> dnsToDelete = new ArrayList<String>();
     try {
       while (ne.hasMore()) {
         SearchResult sr = ne.next();
         dnsToDelete.add(sr.getName() + "," + TRUSTSTORE_DN);
       }
     } finally {
       ne.close();
     }
     for (String dn : dnsToDelete) {
       ctx.destroySubcontext(dn);
     }
   } catch (NameNotFoundException nnfe) {
     // Ignore
     LOG.log(Level.WARNING, "Error cleaning truststore: " + nnfe, nnfe);
   }
 }
Esempio n. 7
0
  /**
   * Initialize this <code>LoginModule</code>.
   *
   * @param subject the <code>Subject</code> to be authenticated.
   * @param callbackHandler a <code>CallbackHandler</code> to acquire the username and password.
   * @param sharedState shared <code>LoginModule</code> state.
   * @param options options specified in the login <code>Configuration</code> for this particular
   *     <code>LoginModule</code>.
   */
  public void initialize(
      Subject subject,
      CallbackHandler callbackHandler,
      Map<String, ?> sharedState,
      Map<String, ?> options) {

    this.subject = subject;
    this.callbackHandler = callbackHandler;
    this.sharedState = sharedState;
    this.options = options;

    ldapEnvironment = new Hashtable(9);
    ldapEnvironment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

    // Add any JNDI properties to the environment
    Set keys = options.keySet();
    String key;
    for (Iterator i = keys.iterator(); i.hasNext(); ) {
      key = (String) i.next();
      if (key.indexOf(".") > -1) {
        ldapEnvironment.put(key, options.get(key));
      }
    }

    // initialize any configured options

    userProvider = (String) options.get(USER_PROVIDER);
    if (userProvider != null) {
      ldapEnvironment.put(Context.PROVIDER_URL, userProvider);
    }

    authcIdentity = (String) options.get(AUTHC_IDENTITY);
    if (authcIdentity != null && (authcIdentity.indexOf(USERNAME_TOKEN) != -1)) {
      identityMatcher = USERNAME_PATTERN.matcher(authcIdentity);
    }

    userFilter = (String) options.get(USER_FILTER);
    if (userFilter != null) {
      if (userFilter.indexOf(USERNAME_TOKEN) != -1) {
        filterMatcher = USERNAME_PATTERN.matcher(userFilter);
      }
      constraints = new SearchControls();
      constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
      constraints.setReturningAttributes(new String[0]); // return no attrs
      constraints.setReturningObjFlag(true); // to get the full DN
    }

    authzIdentity = (String) options.get(AUTHZ_IDENTITY);
    if (authzIdentity != null && authzIdentity.startsWith("{") && authzIdentity.endsWith("}")) {
      if (constraints != null) {
        authzIdentityAttr = authzIdentity.substring(1, authzIdentity.length() - 1);
        constraints.setReturningAttributes(new String[] {authzIdentityAttr});
      }
      authzIdentity = null; // set later, from the specified attribute
    }

    // determine mode
    if (authcIdentity != null) {
      if (userFilter != null) {
        authFirst = true; // authentication-first mode
      } else {
        authOnly = true; // authentication-only mode
      }
    }

    if ("false".equalsIgnoreCase((String) options.get("useSSL"))) {
      useSSL = false;
      ldapEnvironment.remove(Context.SECURITY_PROTOCOL);
    } else {
      ldapEnvironment.put(Context.SECURITY_PROTOCOL, "ssl");
    }

    tryFirstPass = "******".equalsIgnoreCase((String) options.get("tryFirstPass"));

    useFirstPass = "******".equalsIgnoreCase((String) options.get("useFirstPass"));

    storePass = "******".equalsIgnoreCase((String) options.get("storePass"));

    clearPass = "******".equalsIgnoreCase((String) options.get("clearPass"));

    debug = "true".equalsIgnoreCase((String) options.get("debug"));

    if (debug) {
      if (authFirst) {
        System.out.println(
            "\t\t[LdapLoginModule] "
                + "authentication-first mode; "
                + (useSSL ? "SSL enabled" : "SSL disabled"));
      } else if (authOnly) {
        System.out.println(
            "\t\t[LdapLoginModule] "
                + "authentication-only mode; "
                + (useSSL ? "SSL enabled" : "SSL disabled"));
      } else {
        System.out.println(
            "\t\t[LdapLoginModule] "
                + "search-first mode; "
                + (useSSL ? "SSL enabled" : "SSL disabled"));
      }
    }
  }
  private static void updateReplication(
      ServerDescriptor desc, InitialLdapContext ctx, TopologyCacheFilter cacheFilter)
      throws NamingException {
    boolean replicationEnabled = false;
    SearchControls ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
    ctls.setReturningAttributes(new String[] {"ds-cfg-enabled"});
    String filter = "(objectclass=ds-cfg-synchronization-provider)";

    LdapName jndiName =
        new LdapName("cn=Multimaster Synchronization,cn=Synchronization Providers,cn=config");
    NamingEnumeration<SearchResult> syncProviders = null;

    try {
      syncProviders = ctx.search(jndiName, filter, ctls);

      while (syncProviders.hasMore()) {
        SearchResult sr = syncProviders.next();

        if ("true".equalsIgnoreCase(getFirstValue(sr, "ds-cfg-enabled"))) {
          replicationEnabled = true;
        }
      }
    } catch (NameNotFoundException nse) {
      /* ignore */
    } finally {
      if (syncProviders != null) {
        syncProviders.close();
      }
    }
    desc.serverProperties.put(
        ServerProperty.IS_REPLICATION_ENABLED, replicationEnabled ? Boolean.TRUE : Boolean.FALSE);

    Set<String> allReplicationServers = new LinkedHashSet<String>();

    if (cacheFilter.searchBaseDNInformation()) {
      ctls = new SearchControls();
      ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
      ctls.setReturningAttributes(
          new String[] {"ds-cfg-base-dn", "ds-cfg-replication-server", "ds-cfg-server-id"});
      filter = "(objectclass=ds-cfg-replication-domain)";

      jndiName =
          new LdapName("cn=Multimaster Synchronization,cn=Synchronization Providers,cn=config");

      syncProviders = null;
      try {
        syncProviders = ctx.search(jndiName, filter, ctls);

        while (syncProviders.hasMore()) {
          SearchResult sr = syncProviders.next();

          int id = Integer.parseInt(getFirstValue(sr, "ds-cfg-server-id"));
          Set<String> replicationServers = getValues(sr, "ds-cfg-replication-server");
          Set<String> dns = getValues(sr, "ds-cfg-base-dn");
          for (String dn : dns) {
            for (ReplicaDescriptor replica : desc.getReplicas()) {
              if (areDnsEqual(replica.getSuffix().getDN(), dn)) {
                replica.setReplicationId(id);
                // Keep the values of the replication servers in lower case
                // to make use of Sets as String simpler.
                LinkedHashSet<String> repServers = new LinkedHashSet<String>();
                for (String s : replicationServers) {
                  repServers.add(s.toLowerCase());
                }
                replica.setReplicationServers(repServers);
                allReplicationServers.addAll(repServers);
              }
            }
          }
        }
      } catch (NameNotFoundException nse) {
        /* ignore */
      } finally {
        if (syncProviders != null) {
          syncProviders.close();
        }
      }
    }

    ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    ctls.setReturningAttributes(
        new String[] {
          "ds-cfg-replication-port", "ds-cfg-replication-server", "ds-cfg-replication-server-id"
        });
    filter = "(objectclass=ds-cfg-replication-server)";

    jndiName =
        new LdapName("cn=Multimaster " + "Synchronization,cn=Synchronization Providers,cn=config");

    desc.serverProperties.put(ServerProperty.IS_REPLICATION_SERVER, Boolean.FALSE);
    NamingEnumeration<SearchResult> entries = null;
    try {
      entries = ctx.search(jndiName, filter, ctls);

      while (entries.hasMore()) {
        SearchResult sr = entries.next();

        desc.serverProperties.put(ServerProperty.IS_REPLICATION_SERVER, Boolean.TRUE);
        String v = getFirstValue(sr, "ds-cfg-replication-port");
        desc.serverProperties.put(ServerProperty.REPLICATION_SERVER_PORT, Integer.parseInt(v));
        v = getFirstValue(sr, "ds-cfg-replication-server-id");
        desc.serverProperties.put(ServerProperty.REPLICATION_SERVER_ID, Integer.parseInt(v));
        Set<String> values = getValues(sr, "ds-cfg-replication-server");
        // Keep the values of the replication servers in lower case
        // to make use of Sets as String simpler.
        LinkedHashSet<String> repServers = new LinkedHashSet<String>();
        for (String s : values) {
          repServers.add(s.toLowerCase());
        }
        allReplicationServers.addAll(repServers);
        desc.serverProperties.put(
            ServerProperty.EXTERNAL_REPLICATION_SERVERS, allReplicationServers);
      }
    } catch (NameNotFoundException nse) {
      /* ignore */
    } finally {
      if (entries != null) {
        entries.close();
      }
    }

    boolean replicationSecure = false;
    if (replicationEnabled) {
      ctls = new SearchControls();
      ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
      ctls.setReturningAttributes(new String[] {"ds-cfg-ssl-encryption"});
      filter = "(objectclass=ds-cfg-crypto-manager)";

      jndiName = new LdapName("cn=Crypto Manager,cn=config");

      entries = ctx.search(jndiName, filter, ctls);

      try {
        while (entries.hasMore()) {
          SearchResult sr = entries.next();

          String v = getFirstValue(sr, "ds-cfg-ssl-encryption");
          replicationSecure = "true".equalsIgnoreCase(v);
        }
      } finally {
        entries.close();
      }
    }
    desc.serverProperties.put(
        ServerProperty.IS_REPLICATION_SECURE, replicationSecure ? Boolean.TRUE : Boolean.FALSE);
  }
  private static void updateReplicas(
      ServerDescriptor desc, InitialLdapContext ctx, TopologyCacheFilter cacheFilter)
      throws NamingException {
    if (!cacheFilter.searchBaseDNInformation()) {
      return;
    }
    SearchControls ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    ctls.setReturningAttributes(new String[] {"ds-cfg-base-dn", "ds-cfg-backend-id"});
    String filter = "(objectclass=ds-cfg-backend)";

    LdapName jndiName = new LdapName("cn=config");
    NamingEnumeration<SearchResult> databases = ctx.search(jndiName, filter, ctls);

    try {
      while (databases.hasMore()) {
        SearchResult sr = databases.next();

        String id = getFirstValue(sr, "ds-cfg-backend-id");

        if (!isConfigBackend(id) || isSchemaBackend(id)) {
          Set<String> baseDns = getValues(sr, "ds-cfg-base-dn");

          Set<String> entries;
          if (cacheFilter.searchMonitoringInformation()) {
            entries = getBaseDNEntryCount(ctx, id);
          } else {
            entries = new HashSet<String>();
          }

          Set<ReplicaDescriptor> replicas = desc.getReplicas();
          for (String baseDn : baseDns) {
            boolean addReplica = cacheFilter.searchAllBaseDNs();
            if (!addReplica) {
              for (String dn : cacheFilter.getBaseDNsToSearch()) {
                addReplica = Utils.areDnsEqual(dn, baseDn);
                if (addReplica) {
                  break;
                }
              }
            }
            if (addReplica) {
              SuffixDescriptor suffix = new SuffixDescriptor();
              suffix.setDN(baseDn);
              ReplicaDescriptor replica = new ReplicaDescriptor();
              replica.setServer(desc);
              replica.setBackendName(id);
              replicas.add(replica);
              HashSet<ReplicaDescriptor> r = new HashSet<ReplicaDescriptor>();
              r.add(replica);
              suffix.setReplicas(r);
              replica.setSuffix(suffix);
              int nEntries = -1;
              for (String s : entries) {
                int index = s.indexOf(" ");
                if (index != -1) {
                  String dn = s.substring(index + 1);
                  if (Utils.areDnsEqual(baseDn, dn)) {
                    try {
                      nEntries = Integer.parseInt(s.substring(0, index));
                    } catch (Throwable t) {
                      /* Ignore */
                    }
                    break;
                  }
                }
              }
              replica.setEntries(nEntries);
            }
          }
          desc.setReplicas(replicas);
        }
      }
    } finally {
      databases.close();
    }
  }
  /**
   * This method will test if a user has access to the LDAP, if so it will then check the list of
   * groups and check for is access
   *
   * @param String username as named via a uid in the LDAP
   * @param String password clear text in LDAP
   * @return Hashtable authenticate object
   */
  public Hashtable authenticate(String username, String password, String keyfob_id) {

    Hashtable authHT = new Hashtable();

    if (keyfob_id != null) {
      System.out.println("attempted keyfob value: " + keyfob_id);
      // we need to bind with our anon bind user
      username = this.AD_ANON_BIND_UNAME;
      password = this.AD_ANON_BIND_PWORD;
    }

    // assume they will not pass the test
    boolean authenticated = false;

    // first check to see if we even need to hit LDAP (not overridden)
    if (this.LDAP_OVERRIDE) {
      System.out.println("Override Authentication");
      // just check against stored username/password, put in all groups
      if (username.equals(this.LDAP_OVERRIDE_UNAME) && password.equals(this.LDAP_OVERRIDE_PWORD)) {
        authenticated = true;
        // just add then to each group
        for (String key : groups.keySet()) {
          // push the name of the group and access to it boolean
          authHT.put(key, true); // method throws NamingException
        }
      }

    } else {
      // authenticate agianst creditials server
      System.err.println("Trying " + this.PROVIDER_TYPE + " authentication by: " + username);

      try {

        // build a hash table to pass as a bindable event
        // Set up environment for creating initial context
        Hashtable<String, String> env = new Hashtable<String, String>();

        env.put(Context.INITIAL_CONTEXT_FACTORY, this.INITIAL_CONTEXT_FACTORY);

        env.put(Context.SECURITY_AUTHENTICATION, this.SECURITY_AUTHENTICATION);
        // we take the uid to authenticate, pair it with the username, and append the base location
        env.put(Context.PROVIDER_URL, this.PROVIDER_URL);

        if (this.PROVIDER_TYPE.equals("AD")) {
          env.put(Context.SECURITY_PRINCIPAL, username + "@" + this.AD_DOMAIN);
        } else if (this.PROVIDER_TYPE.equals("LDAP")) {
          env.put(
              Context.SECURITY_PRINCIPAL, "uid=" + username + "," + this.USERS_LOC + this.BASE_DN);
        } // we don't need to throw errors here because first try/catch finds it

        env.put(Context.SECURITY_CREDENTIALS, password);

        // send env assigments to console
        // enumerateContents(env.elements());

        /** now that we have our hash values lets go authenticate */

        // first we want to connect to the LDAP Server and create initial context
        // making sure the user name and password are valid
        ctx =
            new InitialDirContext(
                env); // Throws AuthenticationException if not valid username/password
        // WE NEVER GO PAST HERE IF AuthenticationException THROWN
        System.err.println("connection and creditials valid");

        /**
         * we just split the two paths of AD and LDAP authentication because the LDAP way worked and
         * we are migrating to AD. However we want to be able to easily switch back until the LDAP
         * service is discontinued. Theoretically both services should be 'searchable' the same way
         * at some point the LDAP code should be removed or universal code written
         */
        if (this.PROVIDER_TYPE.equals("AD")) {
          /** AD way, get the group list, if they match add */
          SearchControls constraints = new SearchControls();
          constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);

          // either search by user name or by keyfob id. either way will return a user if one is
          // found
          NamingEnumeration results = null;
          if (keyfob_id != null) {
            // we don't challenge on keyfob. assumed if you have keyfob you are that user
            System.out.println("searching for keyfob id: >" + keyfob_id + "<");
            results =
                ctx.search(
                    this.USERS_LOC + this.BASE_DN,
                    "(" + this.ATTRIBUTE_NAME_KEYFOB_ID + "=" + keyfob_id + ")",
                    constraints);
            authHT.put("keyfob_id", keyfob_id); // pass it back as proof positive we found it
          } else {
            results =
                ctx.search(
                    this.USERS_LOC + this.BASE_DN,
                    "(" + this.ATTRIBUTE_NAME_UNAME + "=" + username + ")",
                    constraints);
          }

          while (results != null && results.hasMore()) {
            SearchResult sr = (SearchResult) results.next();
            String dn = sr.getName() + ", " + this.USERS_LOC + this.BASE_DN;

            Attributes ar = ctx.getAttributes(dn, MY_ATTRS);
            if (ar == null) {
              // we need the user to have attributes
              throw new Exception("Entry " + dn + " has none of the specified attributes\n");
            }
            for (int i = 0; i < MY_ATTRS.length; i++) {
              Attribute attr = ar.get(MY_ATTRS[i]);
              if (attr == null) {
                continue;
              }
              System.out.println(MY_ATTRS[i] + ":");
              for (Enumeration vals = attr.getAll(); vals.hasMoreElements(); ) {
                String temp_next_element = vals.nextElement().toString(); // returns generic Object
                System.out.println("\t" + temp_next_element);

                // push the attributes to the auth HT
                if (!(authHT.containsKey(MY_ATTRS[i]))) {
                  // push the name of the group and access to it boolean
                  authHT.put(MY_ATTRS[i], temp_next_element);
                }

                // see if this element value matches any of my groups
                for (String key : groups.keySet()) {
                  if (temp_next_element
                      .toLowerCase()
                      .startsWith("cn=" + groups.get(key).toLowerCase())) {
                    // push the name of the group and access to it boolean
                    authHT.put(key, true);

                    // if user is found in ANY of the predefined groups they are 'authenticated' to
                    // login.
                    // RolemManager.as handles ACL
                    authenticated = true;
                  }
                }
              }
            }
          }

          // now for any groups not found, set them to false
          for (String key : groups.keySet()) {
            if (!(authHT.containsKey(key))) {
              // push the name of the group and access to it boolean
              authHT.put(key, false);
            }
          }

          // end AD WAY

        } else if (this.PROVIDER_TYPE.equals("LDAP")) {
          // authenticated only in the sense they are a valid AD user
          authenticated = true;

          // now that we have verified they are a valid user, lets see what type of access they have
          // groups are specified in the config file as "GROUP_<name>" key=value pairs where value
          // is the LDAP group name
          // and key is what we are looking for in the scheduling app
          for (String key : groups.keySet()) {
            // push the name of the group and access to it boolean
            authHT.put(
                key,
                new Boolean(
                    userInGroup(username, groups.get(key)))); // method throws NamingException
          }
        } else {
          throw new Exception("Provider type not found.");
        }

        // Close the context when we're done
        ctx.close();
      } catch (AuthenticationException e) {
        // binding to LDAP server with provided username/password failed
        // e.printStackTrace();
        System.err.println(
            "AuthenticationException: "
                + e.getMessage()); // outputs -> [LDAP: error code 49 - Invalid Credentials]
        errorStack += e.getMessage() + "\n";
      } catch (NamingException e) {
        // catches invalid DN. Should not be thrown unless changes made to DN
        // Could also fail from the context of the called method userInGroup
        System.err.println("NamingException: " + e.getMessage());
        // e.printStackTrace();
        errorStack += e.getMessage() + "\n";
      } catch (Exception e) {
        e.printStackTrace();
        System.err.println("Exception: " + e.getMessage());
        errorStack += e.getMessage() + "\n";
      } finally { // make sure our connection is closed if relevant
        if (ctx != null) {
          try {
            ctx.close();
          } catch (NamingException e) {
            throw new RuntimeException(e);
          }
        }
      }
    }

    // push whether or not it was authenticated
    authHT.put("authenticated", new Boolean(authenticated));

    // spill contents to catalina.out file
    enumerateContents(authHT.keys());
    enumerateContents(authHT.elements());

    return (authHT);
  }