<commit_before>package com.softartisans.timberwolf.services;

import com.sun.security.auth.callback.TextCallbackHandler;

import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

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.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

/**
 * This class fetches a list of principals through LDAP.
 * It tries to return as many as possible.
 */
public class LdapFetcher implements PrincipalFetcher, PrivilegedAction<Iterable<String>>
{
    private final String domainName;
    private final String configurationEntry;
    private PrincipalFetchException fail;

    public LdapFetcher(final String aDomainName, final String aConfigurationEntry)
    {
        if (aDomainName == null || aDomainName.length() == 0)
        {
            throw new IllegalArgumentException("domainName cannot be empty");
        }
        if (aConfigurationEntry == null || aConfigurationEntry.length() == 0)
        {
            throw new IllegalArgumentException("configurationEntry cannot be empty");
        }
        domainName = aDomainName;
        configurationEntry = aConfigurationEntry;
    }

    public Iterable<String> getPrincipals() throws PrincipalFetchException
    {
        LoginContext lc = loginAsDev(configurationEntry);
        Subject sbj = lc.getSubject();

        Iterable<String> rtn = Subject.doAs(sbj, this);
        if (fail != null)
        {
            throw fail;
        }
        return rtn;
    }

    @Override
    public Iterable<String> run()
    {
        Hashtable<String, String> defEnv = defaultEnvironment();
        List<String> rtnList = new LinkedList<String>();
        try
        {
            DirContext context = new InitialDirContext(defEnv);

            String wantedAttribute = "userPrincipalName";
            SearchControls ctrl = new SearchControls();
            String[] attributeFilter = {
                    wantedAttribute
            };
            ctrl.setReturningAttributes(attributeFilter);
            ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE);
            NamingEnumeration<?> enumeration = context.search("CN=Users", "(objectClass=person)", ctrl);
            while (enumeration.hasMore())
            {
                SearchResult result = (SearchResult) enumeration.next();
                Attributes attribs = result.getAttributes();
                stringifyAttributes(attribs, wantedAttribute, rtnList);
            }

        }
        catch (NamingException e)
        {
            e.printStackTrace();
            fail = new PrincipalFetchException(e);
        }
        return rtnList;
    }

    private Hashtable<String, String> defaultEnvironment()
    {
        final Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        // The secrets about this PROVIDER_URL are contained within:
        // http://docs.oracle.com/javase/6/docs/technotes/guides/jndi/jndi-ldap.html
        // Check out the part about "automatic discovery of LDAP services".
        // Because that's what's happening here.
        env.put(Context.PROVIDER_URL, getProviderDiscoveryURL());
        env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
        return env;
    }

    private static LoginContext loginAsDev(final String configurationEntry) throws PrincipalFetchException
    {
        LoginContext lc = null;
        try
        {
            lc = new LoginContext(configurationEntry, new TextCallbackHandler());
            // Attempt authentication
            // We might want to do this in a "for" loop to give
            // user more than one chance to enter correct username/password
            lc.login();
        }
        catch (LoginException le)
        {
            System.err.println("Authentication attempt failed: " + le);
            throw new PrincipalFetchException(le);
        }

        return lc;
    }

    private static void stringifyAttributes(final Attributes attribs,
                                            final String wantedAttribute,
                                            final Collection<String> collector) throws NamingException
    {
        Attribute attrib = attribs.get(wantedAttribute);
        if (attrib != null)
        {
            NamingEnumeration<?> values = ((BasicAttribute) attrib).getAll();
            while (values.hasMore())
            {
                collector.add(values.next().toString());
            }
        }
    }

    /**
     * Given a domain name, this returns the url
     * used to automatically discover the ldap server.
     */
    public String getProviderDiscoveryURL()
    {
        StringBuilder userDNBuilder = new StringBuilder();
        userDNBuilder.append("ldap:///");
        String[] bits = domainName.split("\\.");
        boolean firstBit = true;
        for (String bit : bits)
        {
            if (firstBit)
            {
                firstBit = false;
            }
            else
            {
                userDNBuilder.append(',');
            }
            userDNBuilder.append("dc=");
            userDNBuilder.append(bit);
        }
        return userDNBuilder.toString();
    }

    /** Queries the domain's LDAP server for supported authentication methods.
     *
     * I'm leaving this hear for the time being because it's quite likely
     * we may face LDAP servers that don't support GSSAPI.
     * @return An iterable listing all supported authentication methods.
     * @throws PrincipalFetchException
     */
    public Iterable<String> getSecurityMechanisms() throws PrincipalFetchException
    {
        try
        {
            Hashtable<String, String> defEnv = defaultEnvironment();
            DirContext ctx = new InitialDirContext(defEnv);

            Attributes attrs = ctx.getAttributes(getProviderDiscoveryURL(),
                                                 new String[]{"supportedSASLMechanisms"});
            List<String> rtnList = new LinkedList<String>();
            stringifyAttributes(attrs, "supportedSASLMechanisms", rtnList);
            return rtnList;

        }
        catch (NamingException e)
        {
            throw new PrincipalFetchException(e);
        }
    }
}<commit_msg>Corrected some ldap stuff after review<commit_after>package com.softartisans.timberwolf.services;

import com.sun.security.auth.callback.TextCallbackHandler;

import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

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.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

/**
 * This class fetches a list of principals through LDAP.
 * It tries to return as many as possible.
 */
public class LdapFetcher implements PrincipalFetcher, PrivilegedAction<Iterable<String>>
{
    private final String domainName;
    private final String configurationEntry;
    private PrincipalFetchException fail;

    public LdapFetcher(final String aDomainName, final String aConfigurationEntry)
    {
        if (aDomainName == null || aDomainName.length() == 0)
        {
            throw new IllegalArgumentException("domainName cannot be empty");
        }
        if (aConfigurationEntry == null || aConfigurationEntry.length() == 0)
        {
            throw new IllegalArgumentException("configurationEntry cannot be empty");
        }
        domainName = aDomainName;
        configurationEntry = aConfigurationEntry;
    }

    public Iterable<String> getPrincipals() throws PrincipalFetchException
    {
        LoginContext lc = login(configurationEntry);
        Subject sbj = lc.getSubject();

        Iterable<String> rtn = Subject.doAs(sbj, this);
        if (fail != null)
        {
            throw fail;
        }
        return rtn;
    }

    /**
     * This will make the actual LDAP call. This is the run function of the
     * privileged action, so it assumes that all authentication has already
     * been taken care of through SASL. This should not be called directly,
     * it's called by Subject.doAs(). You should call getPrincipals, which
     * takes care of logging in. If you're already logged in? Then then this
     * class needs to be touched up to remove all the login stuff.
     *
     * @return A list of principals to get emails for.
     */
    @Override
    public Iterable<String> run()
    {
        Hashtable<String, String> defEnv = defaultEnvironment();
        List<String> rtnList = new LinkedList<String>();
        try
        {
            DirContext context = new InitialDirContext(defEnv);

            String wantedAttribute = "userPrincipalName";
            SearchControls ctrl = new SearchControls();
            String[] attributeFilter = {
                    wantedAttribute
            };
            ctrl.setReturningAttributes(attributeFilter);
            ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE);
            NamingEnumeration<?> enumeration = context.search("CN=Users", "(objectClass=person)", ctrl);
            while (enumeration.hasMore())
            {
                SearchResult result = (SearchResult) enumeration.next();
                Attributes attribs = result.getAttributes();
                Attribute attrib = attribs.get(wantedAttribute);
                if (attrib != null)
                {
                    NamingEnumeration<?> values =
                        ((BasicAttribute) attrib).getAll();
                    while (values.hasMore())
                    {
                        rtnList.add(values.next().toString());
                    }
                }
            }

        }
        catch (NamingException e)
        {
            e.printStackTrace();
            fail = new PrincipalFetchException(e);
        }
        return rtnList;
    }

    private Hashtable<String, String> defaultEnvironment()
    {
        final Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        // The secrets about this PROVIDER_URL are contained within:
        // http://docs.oracle.com/javase/6/docs/technotes/guides/jndi/jndi-ldap.html
        // Check out the part about "automatic discovery of LDAP services".
        // Because that's what's happening here.
        env.put(Context.PROVIDER_URL, getProviderDiscoveryURL());
        env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
        return env;
    }

    /**
     * This will likely be removed down the line once SASL authentication
     * is global to the entire process.
     */
    private static LoginContext login(final String configurationEntry)
        throws PrincipalFetchException
    {
        LoginContext lc = null;
        try
        {
            lc = new LoginContext(configurationEntry, new TextCallbackHandler());
            // Attempt authentication
            // We might want to do this in a "for" loop to give
            // user more than one chance to enter correct username/password
            lc.login();
        }
        catch (LoginException le)
        {
            System.err.println("Authentication attempt failed: " + le);
            throw new PrincipalFetchException(le);
        }

        return lc;
    }

    /**
     * Given a domain name, this returns the url
     * used to automatically discover the ldap server.
     */
    public String getProviderDiscoveryURL()
    {
        StringBuilder userDNBuilder = new StringBuilder();
        userDNBuilder.append("ldap:///");
        String[] bits = domainName.split("\\.");
        boolean firstBit = true;
        for (String bit : bits)
        {
            if (firstBit)
            {
                firstBit = false;
            }
            else
            {
                userDNBuilder.append(',');
            }
            userDNBuilder.append("dc=");
            userDNBuilder.append(bit);
        }
        return userDNBuilder.toString();
    }

    /** Queries the domain's LDAP server for supported authentication methods.
     *
     * I'm leaving this hear for the time being because it's quite likely
     * we may face LDAP servers that don't support GSSAPI.
     * @return An iterable listing all supported authentication methods.
     * @throws PrincipalFetchException
     */
    public Iterable<String> getSecurityMechanisms() throws PrincipalFetchException
    {
        try
        {
            Hashtable<String, String> defEnv = defaultEnvironment();
            DirContext ctx = new InitialDirContext(defEnv);

            Attributes attrs = ctx.getAttributes(getProviderDiscoveryURL(),
                                                 new String[]{"supportedSASLMechanisms"});
            List<String> rtnList = new LinkedList<String>();
            Attribute attrib = attrs.get("supportedSASLMechanisms");
            if (attrib != null)
            {
                NamingEnumeration<?> values =
                    ((BasicAttribute) attrib).getAll();
                while (values.hasMore())
                {
                    rtnList.add(values.next().toString());
                }
            }
            return rtnList;

        }
        catch (NamingException e)
        {
            throw new PrincipalFetchException(e);
        }
    }
}
{'fraction_non_alphanumeric': 0.08774869109947644, 'fraction_numerical': 0.000418848167539267, 'mean_word_length': 2.1772011532490576, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1463882', 'n_tokens_mistral': 3650, 'n_tokens_neox': 3542, 'n_words': 946}