1   package com.atlassian.user.impl.ldap.search.page;
2   
3   import com.atlassian.user.EntityException;
4   import com.atlassian.user.impl.RepositoryException;
5   import com.atlassian.user.impl.ldap.properties.LdapSearchProperties;
6   import com.atlassian.user.impl.ldap.repository.LdapContextFactory;
7   import com.atlassian.user.impl.ldap.search.LDAPPagerInfo;
8   import com.atlassian.user.util.LDAPUtils;
9   import com.atlassian.util.profiling.UtilTimerStack;
10  import org.apache.log4j.Logger;
11  
12  import javax.naming.NamingEnumeration;
13  import javax.naming.NamingException;
14  import javax.naming.directory.*;
15  import java.util.List;
16  
17  public class LDAPMembershipToUsernamePager extends LDAPSingleStringPager
18  {
19      private static final Logger log = Logger.getLogger(LDAPMembershipToUsernamePager.class);
20  
21      public LDAPMembershipToUsernamePager(LdapSearchProperties searchProperties, LdapContextFactory repository, LDAPPagerInfo info)
22      {
23          super(searchProperties, repository, info);
24      }
25  
26      protected List<String> preloadSearchResult(SearchResult result, List<String> prefetched) throws EntityException
27      {
28          DirContext ctx = null;
29          try
30          {
31              Attributes entityAttributes = result.getAttributes();
32              String attributeToFind = returningAttributes[0];
33              Attribute attr = entityAttributes.get(attributeToFind);
34  
35              if (attr != null)
36              {
37                  NamingEnumeration interiorList = attr.getAll();
38                  ctx = repository.getLDAPContext();
39                  while (interiorList.hasMoreElements())
40                      addIfFoundUser(prefetched, (String) interiorList.nextElement(), ctx);
41              }
42          }
43          catch (Throwable t)
44          {
45              log.error("Error converting search result: " + result + " into list of members as usernames.", t);
46          }
47          finally
48          {
49              closeContext(ctx);
50          }
51  
52          return prefetched;
53      }
54  
55      /**
56       * If the dn resolves to a username (by {@link #findByDN}) add it to the prefetched list
57       * otherwise log it and ignore.
58       *
59       * @param ctx an already initialised context which can be used to look up the dn
60       */
61      private void addIfFoundUser(List<String> prefetched, String dn, DirContext ctx)
62      {
63          try
64          {
65              String username = findByDN(dn, ctx);
66              if (username != null)
67                  prefetched.add(username);
68          }
69          catch (RepositoryException e)
70          {
71              log.error("Error resolving dn [ " + dn + " ] to a username", e);
72          }
73      }
74  
75      /**
76       * @param ctx an already initialised context which can be used to look up the dn
77       */
78      private String findByDN(String dn, DirContext ctx) throws RepositoryException
79      {
80          String usernameAttribure = searchProperties.getUsernameAttribute();
81          SearchControls ctls = LDAPUtils.createSearchControls(
82                  new String[]{usernameAttribure}, true, searchProperties.getTimeLimitMillis());
83  
84          try
85          {
86              if (UtilTimerStack.isActive())
87                  UtilTimerStack.push(this.getClass().getName() + "_search_JNDI_RAW_" + searchProperties.getUserFilter());
88  
89              NamingEnumeration<SearchResult> userSearchEnum = ctx.search(dn, searchProperties.getUserFilter(), ctls);
90              if (userSearchEnum.hasMoreElements())
91              {
92                  SearchResult sr = userSearchEnum.next();
93                  if (sr != null && sr.getAttributes() != null && sr.getAttributes().get(usernameAttribure) != null)
94                  {
95                      String username = (String) sr.getAttributes().get(usernameAttribure).get();
96                      if (log.isDebugEnabled())
97                          log.debug("LDAPMembershipToUse.findByDN [ " + dn + " ] username [ " + username + " ]");
98                      return username;
99                  }
100             }
101             return null;
102         }
103 
104         catch (NamingException e)
105         {
106             throw new RepositoryException(e);
107         }
108         finally
109         {
110             if (UtilTimerStack.isActive())
111                 UtilTimerStack.pop(this.getClass().getName() + "_search_JNDI_RAW_" + searchProperties.getUserFilter());
112         }
113 
114     }
115 
116     private void closeContext(DirContext ctx)
117     {
118         try
119         {
120             if (ctx != null)
121                 ctx.close();
122         }
123         catch (NamingException e)
124         {
125             log.warn("Exception closing context", e);
126         }
127     }
128 }