<commit_before>/**
 * License Agreement for OpenSearchServer
 * 
 * Copyright (C) 2014-2015 <NAME> / Jaeksoft
 * 
 * http://www.open-search-server.com
 * 
 * This file is part of OpenSearchServer.
 * 
 * OpenSearchServer is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 * 
 * OpenSearchServer is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * OpenSearchServer. If not, see <http://www.gnu.org/licenses/>.
 **/
package com.jaeksoft.searchlib.util;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;

import org.apache.commons.collections.CollectionUtils;

import com.jaeksoft.searchlib.Logging;

public class ActiveDirectory implements Closeable {

	private final DirContext dirContext;

	private final String domainSearchName;

	public ActiveDirectory(String serverName, String username, String password,
			String domain) throws NamingException {
		if (StringUtils.isEmpty(domain))
			throw new NamingException("The domain is empty");
		Properties properties = new Properties();
		properties.put(Context.INITIAL_CONTEXT_FACTORY,
				"com.sun.jndi.ldap.LdapCtxFactory");
		domainSearchName = getDomainSearch(domain);
		String login = StringUtils.fastConcat(username, "@", domain);
		if (serverName != null) {
			properties.put(Context.PROVIDER_URL,
					StringUtils.fastConcat("ldap://", serverName, ":389"));
		}
		properties.put(Context.SECURITY_PRINCIPAL, login);
		properties.put(Context.SECURITY_CREDENTIALS, password);
		properties.put(Context.REFERRAL, "follow");
		properties.put("java.naming.ldap.attributes.binary", "objectSID");
		dirContext = new InitialLdapContext(properties, null);
	}

	public final static String ATTR_CN = "cn";
	public final static String ATTR_MAIL = "mail";
	public final static String ATTR_GIVENNAME = "givenName";
	public final static String ATTR_MEMBEROF = "memberOf";
	public final static String ATTR_OBJECTSID = "objectSid";
	public final static String ATTR_SAMACCOUNTNAME = "sAMAccountName";
	public final static String ATTR_DN = "DistinguishedName";

	private NamingEnumeration<SearchResult> find(String filterExpr,
			String... returningAttributes) throws NamingException {
		SearchControls searchControls = new SearchControls();
		searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
		searchControls.setReturningAttributes(returningAttributes);
		return dirContext.search(domainSearchName, filterExpr, searchControls);
	}

	public static final Attributes getAttributes(
			NamingEnumeration<SearchResult> result) throws NamingException {
		if (result == null)
			return null;
		if (!result.hasMore())
			return null;
		SearchResult rs = (SearchResult) result.next();
		return rs.getAttributes();
	}

	public NamingEnumeration<SearchResult> findUser(String username)
			throws NamingException {
		return find(StringUtils.fastConcat(
				"(&(objectClass=User)(sAMAccountName=", username, "))"),
				ATTR_CN, ATTR_MAIL, ATTR_GIVENNAME, ATTR_OBJECTSID,
				ATTR_SAMACCOUNTNAME, ATTR_MEMBEROF, ATTR_DN);
	}

	private NamingEnumeration<SearchResult> findGroup(String group)
			throws NamingException {
		return find(StringUtils.fastConcat(
				"(&(objectClass=Group)(sAMAccountName=", group, "))"), ATTR_CN,
				ATTR_MAIL, ATTR_GIVENNAME, ATTR_OBJECTSID, ATTR_SAMACCOUNTNAME,
				ATTR_MEMBEROF, ATTR_DN);
	}

	private void findGroups(Collection<ADGroup> groups,
			Collection<ADGroup> collector, Set<String> searchedGroups)
			throws NamingException {
		if (CollectionUtils.isEmpty(groups))
			return;
		List<ADGroup> newGroups = new ArrayList<ADGroup>();
		for (ADGroup group : groups) {
			if (searchedGroups.contains(group.cn1))
				continue;
			collector.add(group);
			searchedGroups.add(group.cn1);
			NamingEnumeration<SearchResult> result = findGroup(group.cn1);
			Attributes attrs = getAttributes(result);
			if (attrs == null)
				continue;
			collectMemberOf(attrs, newGroups);
		}
		findGroups(newGroups, collector, searchedGroups);
	}

	public void findUserGroups(Attributes userAttrs,
			Collection<ADGroup> collector) throws NamingException {
		List<ADGroup> groups = new ArrayList<ADGroup>();
		ActiveDirectory.collectMemberOf(userAttrs, groups);
		TreeSet<String> searchedGroups = new TreeSet<String>();
		findGroups(groups, collector, searchedGroups);
	}

	public void findUserGroup(String userDN, Collection<ADGroup> collector)
			throws NamingException {
		String filter = StringUtils.fastConcat(
				"(member:1.2.840.113556.1.4.1941:=", userDN, ')');
		NamingEnumeration<SearchResult> results = find(filter, ATTR_DN);
		while (results.hasMore()) {
			SearchResult searchResult = results.next();
			Attributes groupAttrs = searchResult.getAttributes();
			Logging.info("ATTRS: " + groupAttrs.toString());
			ADGroup adGroup = new ADGroup(getStringAttribute(groupAttrs,
					ATTR_DN));
			collector.add(adGroup);
		}
	}

	@Override<commit_msg>More restrictive ActiveDirectory/LDAP query<commit_after>/**
 * License Agreement for OpenSearchServer
 * 
 * Copyright (C) 2014-2015 <NAME> / Jaeksoft
 * 
 * http://www.open-search-server.com
 * 
 * This file is part of OpenSearchServer.
 * 
 * OpenSearchServer is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 * 
 * OpenSearchServer is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * OpenSearchServer. If not, see <http://www.gnu.org/licenses/>.
 **/
package com.jaeksoft.searchlib.util;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;

import org.apache.commons.collections.CollectionUtils;

import com.jaeksoft.searchlib.Logging;

public class ActiveDirectory implements Closeable {

	private final DirContext dirContext;

	private final String domainSearchName;

	public ActiveDirectory(String serverName, String username, String password,
			String domain) throws NamingException {
		if (StringUtils.isEmpty(domain))
			throw new NamingException("The domain is empty");
		Properties properties = new Properties();
		properties.put(Context.INITIAL_CONTEXT_FACTORY,
				"com.sun.jndi.ldap.LdapCtxFactory");

		domainSearchName = getDomainSearch(domain);
		String login = StringUtils.fastConcat(username, "@", domain);
		if (serverName != null) {
			properties.put(Context.PROVIDER_URL,
					StringUtils.fastConcat("ldap://", serverName, ":389"));
		}
		properties.put(Context.SECURITY_PRINCIPAL, login);
		properties.put(Context.SECURITY_CREDENTIALS, password);
		properties.put(Context.REFERRAL, "follow");
		properties.put("java.naming.ldap.attributes.binary", "objectSID");
		dirContext = new InitialLdapContext(properties, null);
	}

	public final static String ATTR_CN = "cn";
	public final static String ATTR_MAIL = "mail";
	public final static String ATTR_GIVENNAME = "givenName";
	public final static String ATTR_MEMBEROF = "memberOf";
	public final static String ATTR_OBJECTSID = "objectSid";
	public final static String ATTR_SAMACCOUNTNAME = "sAMAccountName";
	public final static String ATTR_DN = "DistinguishedName";

	private NamingEnumeration<SearchResult> find(String baseDNPrefix,
			String filterExpr, String... returningAttributes)
			throws NamingException {
		SearchControls searchControls = new SearchControls();
		searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
		searchControls.setReturningAttributes(returningAttributes);
		return dirContext.search(baseDNPrefix + domainSearchName, filterExpr,
				searchControls);
	}

	public static final Attributes getAttributes(
			NamingEnumeration<SearchResult> result) throws NamingException {
		if (result == null)
			return null;
		if (!result.hasMore())
			return null;
		SearchResult rs = (SearchResult) result.next();
		return rs.getAttributes();
	}

	public NamingEnumeration<SearchResult> findUser(String username)
			throws NamingException {
		return find(
				"CN=Users,",
				StringUtils
						.fastConcat(
								"(&(objectClass=User)(samAccountType=805306368)(sAMAccountName=",
								username, "))"), ATTR_CN, ATTR_MAIL,
				ATTR_GIVENNAME, ATTR_OBJECTSID, ATTR_SAMACCOUNTNAME,
				ATTR_MEMBEROF, ATTR_DN);
	}

	private NamingEnumeration<SearchResult> findGroup(String group)
			throws NamingException {
		return find(
				"CN=Users,",
				StringUtils
						.fastConcat(
								"(&(objectClass=Group)(samAccountType=268435456)(sAMAccountName=",
								group, "))"), ATTR_CN, ATTR_MAIL,
				ATTR_GIVENNAME, ATTR_OBJECTSID, ATTR_SAMACCOUNTNAME,
				ATTR_MEMBEROF, ATTR_DN);
	}

	private void findGroups(Collection<ADGroup> groups,
			Collection<ADGroup> collector, Set<String> searchedGroups)
			throws NamingException {
		if (CollectionUtils.isEmpty(groups))
			return;
		List<ADGroup> newGroups = new ArrayList<ADGroup>();
		for (ADGroup group : groups) {
			if (searchedGroups.contains(group.cn1))
				continue;
			collector.add(group);
			searchedGroups.add(group.cn1);
			NamingEnumeration<SearchResult> result = findGroup(group.cn1);
			Attributes attrs = getAttributes(result);
			if (attrs == null)
				continue;
			collectMemberOf(attrs, newGroups);
		}
		findGroups(newGroups, collector, searchedGroups);
	}

	public void findUserGroups(Attributes userAttrs,
			Collection<ADGroup> collector) throws NamingException {
		List<ADGroup> groups = new ArrayList<ADGroup>();
		ActiveDirectory.collectMemberOf(userAttrs, groups);
		TreeSet<String> searchedGroups = new TreeSet<String>();
		findGroups(groups, collector, searchedGroups);
	}

	public void findUserGroup(String userDN, Collection<ADGroup> collector)
			throws NamingException {
		String filter = StringUtils.fastConcat(
				"(member:1.2.840.113556.1.4.1941:=", userDN, ')');
		NamingEnumeration<SearchResult> results = find("CN=Users,", filter,
				ATTR_DN);
		while (results.hasMore()) {
			SearchResult searchResult = results.next();
			Attributes groupAttrs = searchResult.getAttributes();
			Logging.info("ATTRS: " + groupAttrs.toString());
			ADGroup adGroup = new ADGroup(getStringAttribute(groupAttrs,
					ATTR_DN));
			collector.add(adGroup);
		}
	}

	@Override
{'fraction_non_alphanumeric': 0.10092758063143563, 'fraction_numerical': 0.006978129520891839, 'mean_word_length': 5.24442082890542, 'pattern_counts': {'":': 2, '<': 41, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '416606', 'n_tokens_mistral': 3873, 'n_tokens_neox': 3459, 'n_words': 868}