]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/directory/ldap/LdapDao.java
Working read-only WebDav server
[lgpl/argeo-commons.git] / org.argeo.util / src / org / argeo / util / directory / ldap / LdapDao.java
1 package org.argeo.util.directory.ldap;
2
3 import static org.argeo.util.naming.LdapAttrs.objectClass;
4
5 import java.util.ArrayList;
6 import java.util.List;
7
8 import javax.naming.AuthenticationNotSupportedException;
9 import javax.naming.Binding;
10 import javax.naming.InvalidNameException;
11 import javax.naming.NameNotFoundException;
12 import javax.naming.NamingEnumeration;
13 import javax.naming.NamingException;
14 import javax.naming.directory.Attribute;
15 import javax.naming.directory.Attributes;
16 import javax.naming.directory.BasicAttributes;
17 import javax.naming.directory.SearchControls;
18 import javax.naming.directory.SearchResult;
19 import javax.naming.ldap.LdapName;
20 import javax.naming.ldap.Rdn;
21
22 import org.argeo.util.directory.HierarchyUnit;
23 import org.argeo.util.naming.LdapAttrs;
24 import org.argeo.util.naming.LdapObjs;
25
26 /** A user admin based on a LDAP server. */
27 public class LdapDao extends AbstractLdapDirectoryDao {
28 private LdapConnection ldapConnection;
29
30 // public LdapUserAdmin(Dictionary<String, ?> properties) {
31 // this(properties, false);
32 // }
33
34 public LdapDao(AbstractLdapDirectory directory) {
35 super(directory);
36 }
37
38 @Override
39 public void init() {
40 ldapConnection = new LdapConnection(getDirectory().getUri().toString(), getDirectory().cloneConfigProperties());
41 }
42
43 public void destroy() {
44 ldapConnection.destroy();
45 }
46
47 // @Override
48 // protected AbstractUserDirectory scope(User user) {
49 // Dictionary<String, Object> credentials = user.getCredentials();
50 // String username = (String) credentials.get(SHARED_STATE_USERNAME);
51 // if (username == null)
52 // username = user.getName();
53 // Dictionary<String, Object> properties = cloneProperties();
54 // properties.put(Context.SECURITY_PRINCIPAL, username.toString());
55 // Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
56 // byte[] pwd = (byte[]) pwdCred;
57 // if (pwd != null) {
58 // char[] password = DirectoryDigestUtils.bytesToChars(pwd);
59 // properties.put(Context.SECURITY_CREDENTIALS, new String(password));
60 // } else {
61 // properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
62 // }
63 // return new LdapUserAdmin(properties, true);
64 // }
65
66 // protected InitialLdapContext getLdapContext() {
67 // return initialLdapContext;
68 // }
69
70 @Override
71 public Boolean entryExists(LdapName dn) {
72 try {
73 return ldapConnection.entryExists(dn);
74 } catch (NameNotFoundException e) {
75 return false;
76 } catch (NamingException e) {
77 throw new IllegalStateException("Cannot check " + dn, e);
78 }
79 }
80
81 @Override
82 public LdapEntry doGetEntry(LdapName name) throws NameNotFoundException {
83 // if (!entryExists(name))
84 // throw new NameNotFoundException(name + " was not found in " + getDirectory().getBaseDn());
85 try {
86 Attributes attrs = ldapConnection.getAttributes(name);
87
88 LdapEntry res;
89 Rdn technicalRdn = LdapNameUtils.getParentRdn(name);
90 if (getDirectory().getGroupBaseRdn().equals(technicalRdn)) {
91 if (attrs.size() == 0) {// exists but not accessible
92 attrs = new BasicAttributes();
93 attrs.put(LdapAttrs.objectClass.name(), LdapObjs.top.name());
94 attrs.put(LdapAttrs.objectClass.name(), getDirectory().getGroupObjectClass());
95 }
96 res = newGroup(name);
97 } else if (getDirectory().getSystemRoleBaseRdn().equals(technicalRdn)) {
98 if (attrs.size() == 0) {// exists but not accessible
99 attrs = new BasicAttributes();
100 attrs.put(LdapAttrs.objectClass.name(), LdapObjs.top.name());
101 attrs.put(LdapAttrs.objectClass.name(), getDirectory().getGroupObjectClass());
102 }
103 res = newGroup(name);
104 } else if (getDirectory().getUserBaseRdn().equals(technicalRdn)) {
105 if (attrs.size() == 0) {// exists but not accessible
106 attrs = new BasicAttributes();
107 attrs.put(LdapAttrs.objectClass.name(), LdapObjs.top.name());
108 attrs.put(LdapAttrs.objectClass.name(), getDirectory().getUserObjectClass());
109 }
110 res = newUser(name);
111 } else {
112 res = new DefaultLdapEntry(getDirectory(), name);
113 }
114 return res;
115 } catch (NameNotFoundException e) {
116 throw e;
117 } catch (NamingException e) {
118 throw new IllegalStateException("Cannot retrieve entry " + name, e);
119 }
120 }
121
122 // protected boolean isGroup(LdapName dn) {
123 // Rdn technicalRdn = LdapNameUtils.getParentRdn(dn);
124 // if (getDirectory().getGroupBaseRdn().equals(technicalRdn)
125 // || getDirectory().getSystemRoleBaseRdn().equals(technicalRdn))
126 // return true;
127 // else if (getDirectory().getUserBaseRdn().equals(technicalRdn))
128 // return false;
129 // else
130 // throw new IllegalArgumentException(
131 // "Cannot find role type, " + technicalRdn + " is not a technical RDN for " + dn);
132 // }
133
134 @Override
135 public Attributes doGetAttributes(LdapName name) {
136 try {
137 Attributes attrs = ldapConnection.getAttributes(name);
138 return attrs;
139 } catch (NamingException e) {
140 throw new IllegalStateException("Cannot get attributes for " + name);
141 }
142 }
143
144 @Override
145 public List<LdapEntry> doGetEntries(LdapName searchBase, String f, boolean deep) {
146 ArrayList<LdapEntry> res = new ArrayList<>();
147 try {
148 String searchFilter = f != null ? f.toString()
149 : "(|(" + objectClass.name() + "=" + getDirectory().getUserObjectClass() + ")(" + objectClass.name()
150 + "=" + getDirectory().getGroupObjectClass() + "))";
151 SearchControls searchControls = new SearchControls();
152 // only attribute needed is objectClass
153 searchControls.setReturningAttributes(new String[] { objectClass.name() });
154 // FIXME make one level consistent with deep
155 searchControls.setSearchScope(deep ? SearchControls.SUBTREE_SCOPE : SearchControls.ONELEVEL_SCOPE);
156
157 // LdapName searchBase = getBaseDn();
158 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
159
160 results: while (results.hasMoreElements()) {
161 SearchResult searchResult = results.next();
162 Attributes attrs = searchResult.getAttributes();
163 Attribute objectClassAttr = attrs.get(objectClass.name());
164 LdapName dn = toDn(searchBase, searchResult);
165 LdapEntry role;
166 if (objectClassAttr.contains(getDirectory().getGroupObjectClass())
167 || objectClassAttr.contains(getDirectory().getGroupObjectClass().toLowerCase()))
168 role = newGroup(dn);
169 else if (objectClassAttr.contains(getDirectory().getUserObjectClass())
170 || objectClassAttr.contains(getDirectory().getUserObjectClass().toLowerCase()))
171 role = newUser(dn);
172 else {
173 // log.warn("Unsupported LDAP type for " + searchResult.getName());
174 continue results;
175 }
176 res.add(role);
177 }
178 return res;
179 } catch (AuthenticationNotSupportedException e) {
180 // ignore (typically an unsupported anonymous bind)
181 // TODO better logging
182 return res;
183 } catch (NamingException e) {
184 throw new IllegalStateException("Cannot get roles for filter " + f, e);
185 }
186 }
187
188 private LdapName toDn(LdapName baseDn, Binding binding) throws InvalidNameException {
189 return new LdapName(binding.isRelative() ? binding.getName() + "," + baseDn : binding.getName());
190 }
191
192 @Override
193 public List<LdapName> getDirectGroups(LdapName dn) {
194 List<LdapName> directGroups = new ArrayList<LdapName>();
195 try {
196 String searchFilter = "(&(" + objectClass + "=" + getDirectory().getGroupObjectClass() + ")("
197 + getDirectory().getMemberAttributeId() + "=" + dn + "))";
198
199 SearchControls searchControls = new SearchControls();
200 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
201
202 LdapName searchBase = getDirectory().getBaseDn();
203 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
204
205 while (results.hasMoreElements()) {
206 SearchResult searchResult = (SearchResult) results.nextElement();
207 directGroups.add(toDn(searchBase, searchResult));
208 }
209 return directGroups;
210 } catch (NamingException e) {
211 throw new IllegalStateException("Cannot populate direct members of " + dn, e);
212 }
213 }
214
215 @Override
216 public void prepare(LdapEntryWorkingCopy wc) {
217 try {
218 ldapConnection.prepareChanges(wc);
219 } catch (NamingException e) {
220 throw new IllegalStateException("Cannot prepare LDAP", e);
221 }
222 }
223
224 @Override
225 public void commit(LdapEntryWorkingCopy wc) {
226 try {
227 ldapConnection.commitChanges(wc);
228 } catch (NamingException e) {
229 throw new IllegalStateException("Cannot commit LDAP", e);
230 }
231 }
232
233 @Override
234 public void rollback(LdapEntryWorkingCopy wc) {
235 // prepare not impacting
236 }
237
238 /*
239 * HIERARCHY
240 */
241
242 @Override
243 public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
244 List<HierarchyUnit> res = new ArrayList<>();
245 try {
246 String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass
247 + "=" + LdapObjs.organization.name() + "))";
248 // String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass
249 // + "=" + LdapObjs.organization.name() + ")(cn=accounts)(cn=users)(cn=groups))";
250
251 SearchControls searchControls = new SearchControls();
252 searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
253 // no attributes needed
254 searchControls.setReturningAttributes(new String[0]);
255
256 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
257
258 while (results.hasMoreElements()) {
259 SearchResult searchResult = (SearchResult) results.nextElement();
260 LdapName dn = toDn(searchBase, searchResult);
261 // Attributes attrs = searchResult.getAttributes();
262 LdapHierarchyUnit hierarchyUnit = new LdapHierarchyUnit(getDirectory(), dn);
263 if (functionalOnly) {
264 if (hierarchyUnit.isFunctional())
265 res.add(hierarchyUnit);
266 } else {
267 res.add(hierarchyUnit);
268 }
269 }
270 return res;
271 } catch (NamingException e) {
272 throw new IllegalStateException("Cannot get direct hierarchy units ", e);
273 }
274 }
275
276 @Override
277 public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
278 try {
279 if (getDirectory().getBaseDn().equals(dn))
280 return getDirectory();
281 if (!dn.startsWith(getDirectory().getBaseDn()))
282 throw new IllegalArgumentException(dn + " does not start with base DN " + getDirectory().getBaseDn());
283 if (!ldapConnection.entryExists(dn))
284 return null;
285 return new LdapHierarchyUnit(getDirectory(), dn);
286 } catch (NameNotFoundException e) {
287 return null;
288 } catch (NamingException e) {
289 throw new IllegalStateException("Cannot get hierarchy unit " + dn, e);
290 }
291 }
292
293 }