1   package com.atlassian.user.impl.ldap.repository;
2   
3   import com.atlassian.user.impl.RepositoryException;
4   import com.atlassian.user.impl.ldap.properties.LdapConnectionProperties;
5   import com.atlassian.util.profiling.UtilTimerStack;
6   
7   import javax.naming.NamingException;
8   import javax.naming.Context;
9   import javax.naming.directory.DirContext;
10  import javax.naming.directory.InitialDirContext;
11  import java.util.Hashtable;
12  import java.util.Map;
13  import java.util.HashMap;
14  import java.util.Iterator;
15  
16  public class DefaultLdapContextFactory implements LdapContextFactory
17  {
18      private final LdapConnectionProperties connectionProperties;
19  
20      public DefaultLdapContextFactory(LdapConnectionProperties connectionProperties)
21      {
22          this.connectionProperties = connectionProperties;
23      }
24  
25      public Hashtable<String, Object> getJNDIEnv()
26      {
27          Map<String, Object> result = new HashMap<String, Object>();
28  
29          result.put(Context.PROVIDER_URL, connectionProperties.getProviderURL());
30          result.put(Context.INITIAL_CONTEXT_FACTORY, connectionProperties.getJNDIInitialContextFactoryIdentifier());
31          result.put(Context.SECURITY_AUTHENTICATION, connectionProperties.getSecurityAuthentication());
32          result.put(Context.SECURITY_PRINCIPAL, connectionProperties.getSecurityPrincipal());
33          result.put(Context.SECURITY_CREDENTIALS, connectionProperties.getSecurityCredential());
34          result.put(Context.SECURITY_PROTOCOL, connectionProperties.getSecurityProtocol());
35          result.put(Context.BATCHSIZE, Integer.toString(connectionProperties.getSearchBatchSize()));
36          result.put("com.sun.jndi.ldap.connect.timeout", Integer.toString(connectionProperties.getConnectTimeoutMillis()));
37          result.put("com.sun.jndi.ldap.read.timeout", Integer.toString(connectionProperties.getReadTimeoutMillis()));
38  
39          if (connectionProperties.isPoolingOn())
40              result.put("com.sun.jndi.ldap.connect.pool", "true");
41  
42          String referral = System.getProperty("atlassian." + Context.REFERRAL);
43          if (referral != null)
44              result.put(Context.REFERRAL, referral);
45  
46          return createHashtable(result);
47      }
48  
49      public Hashtable getAuthenticationJndiEnvironment(String userDn, String password)
50      {
51          Map<String, Object> env = new HashMap<String, Object>(getJNDIEnv());
52  
53          env.put(Context.SECURITY_PRINCIPAL, userDn);
54          env.put(Context.SECURITY_CREDENTIALS, password);
55  
56          // context used for authentication must have "simple" authentication so that passed in
57          // credentials are _never_ ignored (USER-139)
58          env.put(Context.SECURITY_AUTHENTICATION, "simple");
59  
60          // don't use connection pooling on authentication connections (USER-137)
61          env.put("com.sun.jndi.ldap.connect.pool", "false");
62          return createHashtable(env);
63      }
64  
65      /**
66       * {@link Hashtable}s can't contain <tt>null</tt> as a value or key, so we check each entry in our map before adding
67       * it to the Hashtable.
68       */
69      private <K, V> Hashtable<K, V> createHashtable(Map<K, V> map)
70      {
71          Hashtable<K, V> result = new Hashtable<K, V>();
72          for (Map.Entry<K, V> entry : map.entrySet())
73          {
74              if (entry.getValue() == null || entry.getKey() == null)
75                  continue;
76              result.put(entry.getKey(), entry.getValue());
77          }
78  
79          return result;
80      }
81  
82      public DirContext getLDAPContext() throws RepositoryException
83      {
84          if (UtilTimerStack.isActive())
85              UtilTimerStack.push(this.getClass().getName() + "_getLDAPContext");
86  
87          try
88          {
89              return new InitialDirContext(getJNDIEnv());
90          }
91          catch (NamingException e)
92          {
93              throw new LdapConnectionFailedException(e);
94          }
95          finally
96          {
97              if (UtilTimerStack.isActive())
98                  UtilTimerStack.pop(this.getClass().getName() + "_getLDAPContext");
99          }
100     }
101 }