1 package org
.argeo
.util
.directory
.ldap
;
3 import java
.util
.Dictionary
;
4 import java
.util
.Hashtable
;
6 import javax
.naming
.CommunicationException
;
7 import javax
.naming
.Context
;
8 import javax
.naming
.NameNotFoundException
;
9 import javax
.naming
.NamingEnumeration
;
10 import javax
.naming
.NamingException
;
11 import javax
.naming
.directory
.Attributes
;
12 import javax
.naming
.directory
.DirContext
;
13 import javax
.naming
.directory
.SearchControls
;
14 import javax
.naming
.directory
.SearchResult
;
15 import javax
.naming
.ldap
.InitialLdapContext
;
16 import javax
.naming
.ldap
.LdapName
;
18 import org
.argeo
.util
.naming
.LdapAttrs
;
19 import org
.argeo
.util
.transaction
.WorkingCopy
;
21 /** A synchronized wrapper for a single {@link InitialLdapContext}. */
22 // TODO implement multiple contexts and connection pooling.
23 public class LdapConnection
{
24 private InitialLdapContext initialLdapContext
= null;
26 public LdapConnection(String url
, Dictionary
<String
, ?
> properties
) {
28 Hashtable
<String
, Object
> connEnv
= new Hashtable
<String
, Object
>();
29 connEnv
.put(Context
.INITIAL_CONTEXT_FACTORY
, "com.sun.jndi.ldap.LdapCtxFactory");
30 connEnv
.put(Context
.PROVIDER_URL
, url
);
31 connEnv
.put("java.naming.ldap.attributes.binary", LdapAttrs
.userPassword
.name());
32 // use pooling in order to avoid connection timeout
33 // connEnv.put("com.sun.jndi.ldap.connect.pool", "true");
34 // connEnv.put("com.sun.jndi.ldap.connect.pool.timeout", 300000);
36 initialLdapContext
= new InitialLdapContext(connEnv
, null);
37 // StartTlsResponse tls = (StartTlsResponse) ctx
38 // .extendedOperation(new StartTlsRequest());
40 Object securityAuthentication
= properties
.get(Context
.SECURITY_AUTHENTICATION
);
41 if (securityAuthentication
!= null)
42 initialLdapContext
.addToEnvironment(Context
.SECURITY_AUTHENTICATION
, securityAuthentication
);
44 initialLdapContext
.addToEnvironment(Context
.SECURITY_AUTHENTICATION
, "simple");
45 Object principal
= properties
.get(Context
.SECURITY_PRINCIPAL
);
46 if (principal
!= null) {
47 initialLdapContext
.addToEnvironment(Context
.SECURITY_PRINCIPAL
, principal
.toString());
48 Object creds
= properties
.get(Context
.SECURITY_CREDENTIALS
);
50 initialLdapContext
.addToEnvironment(Context
.SECURITY_CREDENTIALS
, creds
.toString());
53 } catch (NamingException e
) {
54 throw new IllegalStateException("Cannot connect to LDAP", e
);
63 public void destroy() {
66 initialLdapContext
.close();
67 initialLdapContext
= null;
68 } catch (NamingException e
) {
73 protected InitialLdapContext
getLdapContext() {
74 return initialLdapContext
;
77 protected void reconnect() throws NamingException
{
78 initialLdapContext
.reconnect(initialLdapContext
.getConnectControls());
81 public synchronized NamingEnumeration
<SearchResult
> search(LdapName searchBase
, String searchFilter
,
82 SearchControls searchControls
) throws NamingException
{
83 NamingEnumeration
<SearchResult
> results
;
85 results
= getLdapContext().search(searchBase
, searchFilter
, searchControls
);
86 } catch (CommunicationException e
) {
88 results
= getLdapContext().search(searchBase
, searchFilter
, searchControls
);
93 public synchronized Attributes
getAttributes(LdapName name
) throws NamingException
{
95 return getLdapContext().getAttributes(name
);
96 } catch (CommunicationException e
) {
98 return getLdapContext().getAttributes(name
);
102 public synchronized void prepareChanges(WorkingCopy
<?
, ?
, LdapName
> wc
) throws NamingException
{
103 // make sure connection will work
107 for (LdapName dn
: wc
.getDeletedData().keySet()) {
108 if (!entryExists(dn
))
109 throw new IllegalStateException("User to delete no found " + dn
);
112 for (LdapName dn
: wc
.getNewData().keySet()) {
114 throw new IllegalStateException("User to create found " + dn
);
117 for (LdapName dn
: wc
.getModifiedData().keySet()) {
118 if (!wc
.getNewData().containsKey(dn
) && !entryExists(dn
))
119 throw new IllegalStateException("User to modify not found " + dn
);
124 protected boolean entryExists(LdapName dn
) throws NamingException
{
126 return getAttributes(dn
).size() != 0;
127 } catch (NameNotFoundException e
) {
132 public synchronized void commitChanges(LdapEntryWorkingCopy wc
) throws NamingException
{
134 for (LdapName dn
: wc
.getDeletedData().keySet()) {
135 getLdapContext().destroySubcontext(dn
);
138 for (LdapName dn
: wc
.getNewData().keySet()) {
139 LdapEntry user
= wc
.getNewData().get(dn
);
140 getLdapContext().createSubcontext(dn
, user
.getAttributes());
143 for (LdapName dn
: wc
.getModifiedData().keySet()) {
144 Attributes modifiedAttrs
= wc
.getModifiedData().get(dn
);
145 getLdapContext().modifyAttributes(dn
, DirContext
.REPLACE_ATTRIBUTE
, modifiedAttrs
);