]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/directory/ldap/LdapConnection.java
Use runtime namespace context as default.
[lgpl/argeo-commons.git] / org.argeo.util / src / org / argeo / util / directory / ldap / LdapConnection.java
1 package org.argeo.util.directory.ldap;
2
3 import java.util.Dictionary;
4 import java.util.Hashtable;
5
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;
17
18 import org.argeo.util.naming.LdapAttrs;
19 import org.argeo.util.transaction.WorkingCopy;
20
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;
25
26 public LdapConnection(String url, Dictionary<String, ?> properties) {
27 try {
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);
35
36 initialLdapContext = new InitialLdapContext(connEnv, null);
37 // StartTlsResponse tls = (StartTlsResponse) ctx
38 // .extendedOperation(new StartTlsRequest());
39 // tls.negotiate();
40 Object securityAuthentication = properties.get(Context.SECURITY_AUTHENTICATION);
41 if (securityAuthentication != null)
42 initialLdapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, securityAuthentication);
43 else
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);
49 if (creds != null) {
50 initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, creds.toString());
51 }
52 }
53 } catch (NamingException e) {
54 throw new IllegalStateException("Cannot connect to LDAP", e);
55 }
56
57 }
58
59 public void init() {
60
61 }
62
63 public void destroy() {
64 try {
65 // tls.close();
66 initialLdapContext.close();
67 initialLdapContext = null;
68 } catch (NamingException e) {
69 e.printStackTrace();
70 }
71 }
72
73 protected InitialLdapContext getLdapContext() {
74 return initialLdapContext;
75 }
76
77 protected void reconnect() throws NamingException {
78 initialLdapContext.reconnect(initialLdapContext.getConnectControls());
79 }
80
81 public synchronized NamingEnumeration<SearchResult> search(LdapName searchBase, String searchFilter,
82 SearchControls searchControls) throws NamingException {
83 NamingEnumeration<SearchResult> results;
84 try {
85 results = getLdapContext().search(searchBase, searchFilter, searchControls);
86 } catch (CommunicationException e) {
87 reconnect();
88 results = getLdapContext().search(searchBase, searchFilter, searchControls);
89 }
90 return results;
91 }
92
93 public synchronized Attributes getAttributes(LdapName name) throws NamingException {
94 try {
95 return getLdapContext().getAttributes(name);
96 } catch (CommunicationException e) {
97 reconnect();
98 return getLdapContext().getAttributes(name);
99 }
100 }
101
102 public synchronized void prepareChanges(WorkingCopy<?, ?, LdapName> wc) throws NamingException {
103 // make sure connection will work
104 reconnect();
105
106 // delete
107 for (LdapName dn : wc.getDeletedData().keySet()) {
108 if (!entryExists(dn))
109 throw new IllegalStateException("User to delete no found " + dn);
110 }
111 // add
112 for (LdapName dn : wc.getNewData().keySet()) {
113 if (entryExists(dn))
114 throw new IllegalStateException("User to create found " + dn);
115 }
116 // modify
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);
120 }
121
122 }
123
124 protected boolean entryExists(LdapName dn) throws NamingException {
125 try {
126 return getAttributes(dn).size() != 0;
127 } catch (NameNotFoundException e) {
128 return false;
129 }
130 }
131
132 public synchronized void commitChanges(LdapEntryWorkingCopy wc) throws NamingException {
133 // delete
134 for (LdapName dn : wc.getDeletedData().keySet()) {
135 getLdapContext().destroySubcontext(dn);
136 }
137 // add
138 for (LdapName dn : wc.getNewData().keySet()) {
139 LdapEntry user = wc.getNewData().get(dn);
140 getLdapContext().createSubcontext(dn, user.getAttributes());
141 }
142 // modify
143 for (LdapName dn : wc.getModifiedData().keySet()) {
144 Attributes modifiedAttrs = wc.getModifiedData().get(dn);
145 getLdapContext().modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, modifiedAttrs);
146 }
147 }
148 }