/**
   * Retrieve the input attributes from the Active Directory for the given search query
   *
   * <p>Method getAttributes.
   *
   * @param searchBase String
   * @return List<User>
   * @throws NamingException
   */
  private final List<User> getAttributes(String searchBase) throws NamingException {
    LOGGER.info(">> getAttributes()");

    NamingEnumeration<SearchResult> results =
        localInitialLdapContext.search(searchBase, searchFilter, searchctls);

    List<User> users = new ArrayList<User>();
    User user = null;

    while (results.hasMoreElements()) {
      user = new User();
      SearchResult searchResult = results.next();
      Attributes attrs = searchResult.getAttributes();

      if (attrs != null && attrs.size() != 0) {
        Attribute attribute = null;

        String[] retrieveAttributes = parameters.getRetrieveAttributes();
        String[] attributesValues = new String[retrieveAttributes.length];
        for (int i = 0; i < retrieveAttributes.length; i++) {
          attribute = attrs.get(retrieveAttributes[i]);
          if (attribute != null && attribute.get() != null) {
            if (!isNullOrEmpty(attribute.get().toString())) {
              attributesValues[i] = attribute.get().toString();
            }
          }
        }
        user.setAttributeValues(attributesValues);
      }
      users.add(user);
    }

    LOGGER.info("<< getAttributes()");
    return users;
  }
  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();
    }
  }
 /**
  * Method used to know if we are connected as administrator in a server with a given
  * InitialLdapContext.
  *
  * @param ctx the context.
  * @return <CODE>true</CODE> if we are connected and read the configuration and <CODE>false</CODE>
  *     otherwise.
  */
 public static boolean connectedAsAdministrativeUser(InitialLdapContext ctx) {
   boolean connectedAsAdministrativeUser = false;
   try {
     /*
      * Search for the config to check that it is the directory manager.
      */
     SearchControls searchControls = new SearchControls();
     searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
     searchControls.setReturningAttributes(new String[] {SchemaConstants.NO_ATTRIBUTES});
     NamingEnumeration<SearchResult> sr = ctx.search("cn=config", "objectclass=*", searchControls);
     try {
       while (sr.hasMore()) {
         sr.next();
       }
     } finally {
       try {
         sr.close();
       } catch (Exception ex) {
         LOG.log(Level.WARNING, "Unexpected error closing enumeration on cn=Config entry", ex);
       }
     }
     connectedAsAdministrativeUser = true;
   } catch (NamingException ne) {
     // Nothing to do.
   } catch (Throwable t) {
     throw new IllegalStateException("Unexpected throwable.", t);
   }
   return connectedAsAdministrativeUser;
 }
  /* Return all groups for principal == null or all groups for which principal
   * is a member
   *
   */
  private Collection<BwGroup> getGroups(
      final DirConfigProperties dirProps, final BwPrincipal principal) throws CalFacadeException {
    LdapConfigProperties props = (LdapConfigProperties) dirProps;
    InitialLdapContext ctx = null;
    String member = null;

    if (principal != null) {
      if (principal.getKind() == WhoDefs.whoTypeUser) {
        member = getUserEntryValue(props, principal);
      } else if (principal.getKind() == WhoDefs.whoTypeGroup) {
        member = getGroupEntryValue(props, principal);
      }
    }

    try {
      ctx = createLdapInitContext(props);

      BasicAttributes matchAttrs = new BasicAttributes(true);

      if (member != null) {
        matchAttrs.put(props.getGroupMemberAttr(), member);
      }

      String[] idAttr = {props.getGroupIdAttr()};

      ArrayList<BwGroup> groups = new ArrayList<BwGroup>();
      NamingEnumeration response = ctx.search(props.getGroupContextDn(), matchAttrs, idAttr);
      while (response.hasMore()) {
        SearchResult sr = (SearchResult) response.next();
        Attributes attrs = sr.getAttributes();

        Attribute nmAttr = attrs.get(props.getGroupIdAttr());
        if (nmAttr.size() != 1) {
          throw new CalFacadeException("org.bedework.ldap.groups.multiple.result");
        }

        BwGroup group = new BwGroup();
        group.setAccount(nmAttr.get(0).toString());
        group.setPrincipalRef(makePrincipalUri(group.getAccount(), WhoDefs.whoTypeGroup));

        groups.add(group);
      }

      return groups;
    } catch (Throwable t) {
      if (debug) {
        error(t);
      }
      throw new CalFacadeException(t);
    } finally {
      // Close the context to release the connection
      if (ctx != null) {
        closeContext(ctx);
      }
    }
  }
  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();
    }
  }
  public boolean existsUser(String userId) {

    InitialLdapContext ctx = null;
    boolean exists = false;
    try {
      ctx = buildInitialLdapContext();

      String userContext = this.config.getProperty(USER_CTX);
      String userFilter = this.config.getProperty(USER_FILTER);
      String userAttrId = this.config.getProperty(USER_ATTR_ID, "uid");

      userFilter = userFilter.replaceAll("\\{0\\}", userId);

      if (logger.isDebugEnabled()) {
        logger.debug(
            "Seaching for user existence with filter " + userFilter + " on context " + userContext);
      }

      SearchControls constraints = new SearchControls();

      NamingEnumeration<SearchResult> result = ctx.search(userContext, userFilter, constraints);
      if (result.hasMore()) {

        SearchResult sr = result.next();
        Attribute ldapUserId = sr.getAttributes().get(userAttrId);

        if (ldapUserId.contains(userId)) {
          exists = true;
        }
        if (logger.isDebugEnabled()) {
          logger.debug(
              "Entry in LDAP found and result of matching with given user id is " + exists);
        }
      }
      result.close();

    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (ctx != null) {
        try {
          ctx.close();
        } catch (NamingException e) {
          e.printStackTrace();
        }
      }
    }

    return exists;
  }
Example #7
0
  public Iterator<OrganizationalEntity> getMembersForGroup(Group group) {
    InitialLdapContext ctx = null;
    List<OrganizationalEntity> memebers = new ArrayList<OrganizationalEntity>();
    try {
      ctx = buildInitialLdapContext();

      String roleContext = this.config.getProperty(ROLE_CTX);
      String roleFilter =
          this.config.getProperty(ROLE_MEMBERS_FILTER, this.config.getProperty(ROLE_FILTER));
      String roleAttrId = this.config.getProperty(MEMBER_ATTR_ID, "member");

      String entityId = group.getId();
      if (Boolean.parseBoolean(this.config.getProperty(IS_ENTITY_ID_DN, "false"))) {
        entityId = extractUserId(entityId, group);
      }

      roleFilter = roleFilter.replaceAll("\\{0\\}", entityId);

      SearchControls constraints = new SearchControls();
      String searchScope = this.config.getProperty(SEARCH_SCOPE);
      if (searchScope != null) {
        constraints.setSearchScope(parseSearchScope(searchScope));
      }

      NamingEnumeration<SearchResult> result = ctx.search(roleContext, roleFilter, constraints);
      while (result.hasMore()) {
        SearchResult sr = result.next();
        Attribute member = sr.getAttributes().get(roleAttrId);
        for (int i = 0; i < member.size(); i++) {
          User user = TaskModelProvider.getFactory().newUser();
          ((InternalOrganizationalEntity) user).setId(member.get(i).toString());
          memebers.add(user);
        }
      }
      result.close();

    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (ctx != null) {
        try {
          ctx.close();
        } catch (NamingException e) {
          e.printStackTrace();
        }
      }
    }
    return memebers.iterator();
  }
Example #8
0
  public boolean hasEmail(Group group) {
    InitialLdapContext ctx = null;
    boolean exists = false;
    try {
      ctx = buildInitialLdapContext();

      String roleContext = this.config.getProperty(ROLE_CTX);
      String roleFilter = this.config.getProperty(ROLE_FILTER);
      String roleAttrId = this.config.getProperty(EMAIL_ATTR_ID, "mail");

      String entityId = group.getId();
      if (Boolean.parseBoolean(this.config.getProperty(IS_ENTITY_ID_DN, "false"))) {
        entityId = extractUserId(entityId, group);
      }

      roleFilter = roleFilter.replaceAll("\\{0\\}", entityId);

      SearchControls constraints = new SearchControls();
      String searchScope = this.config.getProperty(SEARCH_SCOPE);
      if (searchScope != null) {
        constraints.setSearchScope(parseSearchScope(searchScope));
      }

      NamingEnumeration<SearchResult> result = ctx.search(roleContext, roleFilter, constraints);
      if (result.hasMore()) {
        SearchResult sr = result.next();
        Attribute ldapGroupEmail = sr.getAttributes().get(roleAttrId);

        if (ldapGroupEmail != null && ldapGroupEmail.get() != null) {
          exists = true;
        }
      }
      result.close();

    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (ctx != null) {
        try {
          ctx.close();
        } catch (NamingException e) {
          e.printStackTrace();
        }
      }
    }
    return exists;
  }
  public boolean existsGroup(String groupId) {

    InitialLdapContext ctx = null;
    boolean exists = false;
    try {
      ctx = buildInitialLdapContext();

      String roleContext = this.config.getProperty(ROLE_CTX);
      String roleFilter = this.config.getProperty(ROLE_FILTER);
      String roleAttrId = this.config.getProperty(ROLE_ATTR_ID, "cn");

      roleFilter = roleFilter.replaceAll("\\{0\\}", groupId);

      SearchControls constraints = new SearchControls();
      String searchScope = this.config.getProperty(SEARCH_SCOPE);
      if (searchScope != null) {
        constraints.setSearchScope(parseSearchScope(searchScope));
      }

      NamingEnumeration<SearchResult> result = ctx.search(roleContext, roleFilter, constraints);
      if (result.hasMore()) {
        SearchResult sr = result.next();
        Attribute ldapUserId = sr.getAttributes().get(roleAttrId);

        if (ldapUserId.contains(groupId)) {
          exists = true;
        }
      }
      result.close();

    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (ctx != null) {
        try {
          ctx.close();
        } catch (NamingException e) {
          e.printStackTrace();
        }
      }
    }

    return exists;
  }
  /* Search for a group to ensure it exists
   *
   */
  private BwGroup findGroup(final DirConfigProperties dirProps, final String groupName)
      throws CalFacadeException {
    LdapConfigProperties props = (LdapConfigProperties) dirProps;
    InitialLdapContext ctx = null;

    try {
      ctx = createLdapInitContext(props);

      BasicAttributes matchAttrs = new BasicAttributes(true);

      matchAttrs.put(props.getGroupIdAttr(), groupName);

      String[] idAttr = {props.getGroupIdAttr()};

      BwGroup group = null;
      NamingEnumeration response = ctx.search(props.getGroupContextDn(), matchAttrs, idAttr);
      while (response.hasMore()) {
        //        SearchResult sr = (SearchResult)response.next();
        //        Attributes attrs = sr.getAttributes();

        if (group != null) {
          throw new CalFacadeException("org.bedework.ldap.groups.multiple.result");
        }

        group = new BwGroup();
        group.setAccount(groupName);
        group.setPrincipalRef(makePrincipalUri(groupName, WhoDefs.whoTypeGroup));
      }

      return group;
    } catch (Throwable t) {
      if (debug) {
        error(t);
      }
      throw new CalFacadeException(t);
    } finally {
      // Close the context to release the connection
      if (ctx != null) {
        closeContext(ctx);
      }
    }
  }
  /**
   * @param ctx - the context to search from
   * @param user - the input username
   * @param credential - the bind credential
   * @param baseDN - base DN to search the ctx from
   * @param filter - the search filter string
   * @return the userDN string for the successful authentication
   * @throws NamingException
   */
  @SuppressWarnings("rawtypes")
  protected String bindDNAuthentication(
      InitialLdapContext ctx, String user, Object credential, String baseDN, String filter)
      throws NamingException {
    SearchControls constraints = new SearchControls();
    constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
    constraints.setTimeLimit(searchTimeLimit);
    String attrList[] = {distinguishedNameAttribute};
    constraints.setReturningAttributes(attrList);

    NamingEnumeration results = null;

    Object[] filterArgs = {user};
    results = ctx.search(baseDN, filter, filterArgs, constraints);
    if (results.hasMore() == false) {
      results.close();
      throw PicketBoxMessages.MESSAGES.failedToFindBaseContextDN(baseDN);
    }

    SearchResult sr = (SearchResult) results.next();
    String name = sr.getName();
    String userDN = null;
    Attributes attrs = sr.getAttributes();
    if (attrs != null) {
      Attribute dn = attrs.get(distinguishedNameAttribute);
      if (dn != null) {
        userDN = (String) dn.get();
      }
    }
    if (userDN == null) {
      if (sr.isRelative() == true) userDN = name + ("".equals(baseDN) ? "" : "," + baseDN);
      else throw PicketBoxMessages.MESSAGES.unableToFollowReferralForAuth(name);
    }

    safeClose(results);
    results = null;

    InitialLdapContext userCtx = constructInitialLdapContext(userDN, credential);
    safeClose(userCtx);

    return userDN;
  }
 public static SearchResult searchUnique(String searchFilter, InitialLdapContext ctx)
     throws IllegalStateException, NamingException {
   ctx.setRequestControls(null);
   SearchControls searchControls = new SearchControls();
   searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
   searchControls.setTimeLimit(1000);
   NamingEnumeration<?> namingEnum =
       ctx.search(MessagingServletConfig.ldapBaseDn, searchFilter, searchControls);
   if (namingEnum.hasMore()) {
     SearchResult result = (SearchResult) namingEnum.next();
     if (namingEnum.hasMore()) {
       throw new LimitExceededException(
           "search with filter " + searchFilter + " returned more than 1 result");
     }
     namingEnum.close();
     return result;
   } else {
     throw new NameNotFoundException("search with filter " + searchFilter + " returned no result");
   }
 }
Example #13
0
  protected String searchLdap(
      String context, String filter, String attrId, OrganizationalEntity entity) {
    InitialLdapContext ctx = null;
    String result = null;
    try {
      ctx = buildInitialLdapContext();
      String entityId = entity.getId();
      if (Boolean.parseBoolean(this.config.getProperty(IS_ENTITY_ID_DN, "false"))) {
        entityId = extractUserId(entityId, entity);
      }
      filter = filter.replaceAll("\\{0\\}", entityId);

      SearchControls constraints = new SearchControls();
      String searchScope = this.config.getProperty(SEARCH_SCOPE);
      if (searchScope != null) {
        constraints.setSearchScope(parseSearchScope(searchScope));
      }

      NamingEnumeration<SearchResult> ldapResult = ctx.search(context, filter, constraints);
      if (ldapResult.hasMore()) {
        SearchResult sr = ldapResult.next();
        Attribute entry = sr.getAttributes().get(attrId);
        if (entry != null) {
          result = (String) entry.get();
        }
      }
      ldapResult.close();

    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (ctx != null) {
        try {
          ctx.close();
        } catch (NamingException e) {
          e.printStackTrace();
        }
      }
    }
    return result;
  }
 /**
  * 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;
       }
     }
   }
 }
  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();
    }
  }
  /**
   * 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;
  }
 /**
  * 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);
   }
 }
  /* Find members for given group
   *
   */
  private void getGroupMembers(final DirConfigProperties dirProps, final BwGroup group)
      throws CalFacadeException {
    LdapConfigProperties props = (LdapConfigProperties) dirProps;
    InitialLdapContext ctx = null;

    try {
      ctx = createLdapInitContext(props);

      BasicAttributes matchAttrs = new BasicAttributes(true);

      matchAttrs.put(props.getGroupIdAttr(), group.getAccount());

      String[] memberAttr = {props.getGroupMemberAttr()};

      ArrayList<String> mbrs = null;

      boolean beenHere = false;

      NamingEnumeration response = ctx.search(props.getGroupContextDn(), matchAttrs, memberAttr);
      while (response.hasMore()) {
        SearchResult sr = (SearchResult) response.next();
        Attributes attrs = sr.getAttributes();

        if (beenHere) {
          throw new CalFacadeException("org.bedework.ldap.groups.multiple.result");
        }

        beenHere = true;

        Attribute membersAttr = attrs.get(props.getGroupMemberAttr());
        mbrs = new ArrayList<String>();

        for (int m = 0; m < membersAttr.size(); m++) {
          mbrs.add(membersAttr.get(m).toString());
        }
      }
      // LDAP We need a way to search recursively for groups.

      /* Search for each user in the group */
      String memberContext = props.getGroupMemberContextDn();
      String memberSearchAttr = props.getGroupMemberSearchAttr();
      String[] idAttr = {
        props.getGroupMemberUserIdAttr(), props.getGroupMemberGroupIdAttr(), "objectclass"
      };

      for (String mbr : mbrs) {
        if (memberContext != null) {
          matchAttrs = new BasicAttributes(true);

          matchAttrs.put(memberSearchAttr, mbr);

          response = ctx.search(memberContext, matchAttrs, idAttr);
        } else {
          response = ctx.search(memberContext, null, idAttr);
        }

        if (response.hasMore()) {
          SearchResult sr = (SearchResult) response.next();
          Attributes attrs = sr.getAttributes();

          Attribute ocsAttr = attrs.get("objectclass");
          String userOc = props.getUserObjectClass();
          String groupOc = props.getGroupObjectClass();
          boolean isGroup = false;

          for (int oci = 0; oci < ocsAttr.size(); oci++) {
            String oc = ocsAttr.get(oci).toString();
            if (userOc.equals(oc)) {
              break;
            }

            if (groupOc.equals(oc)) {
              isGroup = true;
              break;
            }
          }

          BwPrincipal p = null;
          Attribute attr;

          if (isGroup) {
            p = BwPrincipal.makeGroupPrincipal();

            attr = attrs.get(props.getGroupMemberGroupIdAttr());
          } else {
            p = BwPrincipal.makeUserPrincipal();

            attr = attrs.get(props.getGroupMemberUserIdAttr());
          }

          if (attr.size() != 1) {
            throw new CalFacadeException("org.bedework.ldap.groups.multiple.result");
          }

          p.setAccount(attr.get(0).toString());
          p.setPrincipalRef(makePrincipalUri(p.getAccount(), p.getKind()));
          group.addGroupMember(p);
        }
      }
    } catch (Throwable t) {
      if (debug) {
        error(t);
      }
      throw new CalFacadeException(t);
    } finally {
      // Close the context to release the connection
      if (ctx != null) {
        closeContext(ctx);
      }
    }

    /* Recursively fetch members of groups that are members. */

    for (BwGroup g : group.getGroups()) {
      getGroupMembers(props, g);
    }
  }
Example #19
0
  /**
   * Register instance key-pair public-key certificate provided in serverProperties: generate a
   * key-id attribute if one is not provided (as expected); add an instance key public-key
   * certificate entry for the key certificate; and associate the certificate entry with the server
   * entry via the key ID attribute.
   *
   * @param ctx the InitialLdapContext on the server we want to update.
   * @param serverProperties Properties of the server being registered to which the instance key
   *     entry belongs.
   * @param serverEntryDn The server's ADS entry DN.
   * @throws ADSContextException In case some JNDI operation fails or there is a problem getting the
   *     instance public key certificate ID.
   */
  void registerInstanceKeyCertificate(
      InitialLdapContext ctx, Map<ServerProperty, Object> serverProperties, LdapName serverEntryDn)
      throws ADSContextException {
    assert serverProperties.containsKey(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE);
    if (!serverProperties.containsKey(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) {
      return;
    }

    // the key ID might be supplied in serverProperties (although, I am unaware of any such case).
    String keyID = (String) serverProperties.get(ServerProperty.INSTANCE_KEY_ID);

    /* these attributes are used both to search for an existing certificate
    entry and, if one does not exist, add a new certificate entry */
    final BasicAttributes keyAttrs = new BasicAttributes();
    final Attribute oc = new BasicAttribute("objectclass");
    oc.add("top");
    oc.add("ds-cfg-instance-key");
    keyAttrs.put(oc);
    if (null != keyID) {
      keyAttrs.put(new BasicAttribute(ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyID));
    }
    keyAttrs.put(
        new BasicAttribute(
            ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE.getAttributeName() + ";binary",
            serverProperties.get(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)));

    /* search for public-key certificate entry in ADS DIT */
    final String attrIDs[] = {"ds-cfg-key-id"};
    NamingEnumeration<SearchResult> results = null;
    try {
      results = ctx.search(ADSContext.getInstanceKeysContainerDN(), keyAttrs, attrIDs);
      boolean found = false;
      while (results.hasMore()) {
        final Attribute keyIdAttr = results.next().getAttributes().get(attrIDs[0]);
        if (null != keyIdAttr) {
          /* attribute ds-cfg-key-id is the entry is a MUST in the schema */
          keyID = (String) keyIdAttr.get();
        }
        found = true;
      }
      /* TODO: It is possible (but unexpected) that the caller specifies a
      ds-cfg-key-id value for which there is a certificate entry in ADS, but
      the certificate value does not match that supplied by the caller. The
      above search would not return the entry, but the below attempt to add
      an new entry with the supplied ds-cfg-key-id will fail (throw a
      NameAlreadyBoundException) */
      if (!found) {
        /* create key ID, if it was not supplied in serverProperties */
        if (null == keyID) {
          keyID =
              CryptoManagerImpl.getInstanceKeyID(
                  (byte[]) serverProperties.get(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE));
          keyAttrs.put(
              new BasicAttribute(ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyID));
        }

        /* add public-key certificate entry */
        final LdapName keyDn =
            new LdapName(
                ServerProperty.INSTANCE_KEY_ID.getAttributeName()
                    + "="
                    + Rdn.escapeValue(keyID)
                    + ","
                    + ADSContext.getInstanceKeysContainerDN());
        ctx.createSubcontext(keyDn, keyAttrs).close();
      }

      if (serverEntryDn != null) {
        /* associate server entry with certificate entry via key ID attribute */
        ctx.modifyAttributes(
            serverEntryDn,
            InitialLdapContext.REPLACE_ATTRIBUTE,
            new BasicAttributes(ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyID));
      }
    } catch (NamingException | CryptoManagerException ne) {
      throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, ne);
    } finally {
      handleCloseNamingEnumeration(results);
    }
  }
  public List<String> getGroupsForUser(
      String userId, List<String> groupIds, List<String> allExistingGroupIds) {

    InitialLdapContext ctx = null;
    List<String> userGroups = new ArrayList<String>();
    try {
      ctx = buildInitialLdapContext();

      String userDN = null;
      // if user id is not DN look it up first in ldap
      if (!Boolean.parseBoolean(this.config.getProperty(IS_USER_ID_DN, "false"))) {
        logger.debug("User id is not DN, looking up user first...");

        String userContext = this.config.getProperty(USER_CTX);
        String userFilter = this.config.getProperty(USER_FILTER);

        userFilter = userFilter.replaceAll("\\{0\\}", userId);
        SearchControls constraints = new SearchControls();
        String searchScope = this.config.getProperty(SEARCH_SCOPE);
        if (searchScope != null) {
          constraints.setSearchScope(parseSearchScope(searchScope));
        }

        logger.debug("Searching for user DN with filter {} on context {}", userFilter, userContext);

        NamingEnumeration<SearchResult> result = ctx.search(userContext, userFilter, constraints);
        if (result.hasMore()) {
          SearchResult searchResult = result.nextElement();
          userDN = searchResult.getNameInNamespace();
          logger.debug("User DN found, DN is {}", userDN);
        }
        result.close();
      }

      String roleContext =
          this.config.getProperty(USER_ROLES_CTX, this.config.getProperty(ROLE_CTX));
      String roleFilter = this.config.getProperty(USER_ROLES_FILTER);
      String roleAttrId = this.config.getProperty(ROLE_ATTR_ID, "cn");

      roleFilter = roleFilter.replaceAll("\\{0\\}", (userDN != null ? userDN : userId));
      SearchControls constraints = new SearchControls();
      String searchScope = this.config.getProperty(SEARCH_SCOPE);
      if (searchScope != null) {
        constraints.setSearchScope(parseSearchScope(searchScope));
      }

      logger.debug(
          "Searching for groups for user with filter {} on context {}", roleFilter, roleContext);

      NamingEnumeration<SearchResult> result = ctx.search(roleContext, roleFilter, constraints);
      if (result.hasMore()) {
        SearchResult searchResult = null;
        String name = null;
        while (result.hasMore()) {
          searchResult = result.nextElement();
          name = (String) searchResult.getAttributes().get(roleAttrId).get();
          logger.debug("Found group {}", name);

          userGroups.add(name);
        }
      }
      result.close();

    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (ctx != null) {
        try {
          ctx.close();
        } catch (NamingException e) {
          e.printStackTrace();
        }
      }
    }
    return userGroups;
  }
  /**
   * Handle a {@code Callback}
   *
   * @param c callback
   * @throws UnsupportedCallbackException If the callback is not supported by this handler
   * @throws NamingException
   */
  protected void handleCallBack(Callback c) throws UnsupportedCallbackException, NamingException {
    if (c instanceof VerifyPasswordCallback) {
      verifyPassword((VerifyPasswordCallback) c);
      return;
    }

    if (c instanceof PasswordCallback == false) return;

    PasswordCallback passwdCallback = (PasswordCallback) c;

    String bindDN = getBindDN();

    String bindCredential = getBindCredential();

    String tmp = options.get(PASSWORD_ATTRIBUTE_ID);
    if (tmp != null && tmp.length() > 0) {
      passwordAttributeID = tmp;
    }

    InitialLdapContext ctx;
    ClassLoader currentTCCL = SecurityActions.getContextClassLoader();
    try {
      if (currentTCCL != null) SecurityActions.setContextClassLoader(null);
      ctx = this.constructInitialLdapContext(bindDN, bindCredential);
    } catch (NamingException e) {
      throw new RuntimeException(e);
    }

    String timeLimit = (String) options.get(SEARCH_TIME_LIMIT_OPT);
    if (timeLimit != null) {
      try {
        searchTimeLimit = Integer.parseInt(timeLimit);
      } catch (NumberFormatException e) {
      }
    }
    if (searchTimeLimit == 0) searchTimeLimit = 10000;

    String baseDN = options.get(BASE_CTX_DN);
    String baseFilter = options.get(BASE_FILTER_OPT);

    SearchControls constraints = new SearchControls();
    constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);

    constraints.setTimeLimit(searchTimeLimit);

    NamingEnumeration<SearchResult> results = null;

    Object[] filterArgs = {userName};
    try {
      if (baseDN == null) throw PicketBoxMessages.MESSAGES.invalidNullBaseContextDN();
      results = ctx.search(baseDN, baseFilter, filterArgs, constraints);
      if (results.hasMore() == false) {
        safeClose(results);
        throw PicketBoxMessages.MESSAGES.failedToFindBaseContextDN(baseDN);
      }
      SearchResult sr = results.next();
      String name = sr.getName();
      String userDN = null;
      if (sr.isRelative() == true) userDN = name + "," + baseDN;
      else throw PicketBoxMessages.MESSAGES.unableToFollowReferralForAuth(name);
      ;

      safeClose(results);

      // Finished Authentication.  Lets look for the attributes
      filterArgs = new Object[] {userName, userDN};
      results = ctx.search(userDN, baseFilter, filterArgs, constraints);
      try {
        while (results.hasMore()) {
          sr = results.next();
          Attributes attributes = sr.getAttributes();
          NamingEnumeration<? extends javax.naming.directory.Attribute> ne = attributes.getAll();

          while (ne != null && ne.hasMoreElements()) {
            javax.naming.directory.Attribute ldapAtt = ne.next();
            if (passwordAttributeID.equalsIgnoreCase(ldapAtt.getID())) {
              Object thePass = ldapAtt.get();
              setPasswordCallbackValue(thePass, passwdCallback);
            }
          }
        }
      } finally {
        safeClose(results);
        safeClose(ctx);
        if (currentTCCL != null) SecurityActions.setContextClassLoader(currentTCCL);
      }
    } catch (NamingException ne) {
      PicketBoxLogger.LOGGER.error(ne);
    }
  }
  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();
    }
  }