]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/directory/ldap/LdapDao.java
JDK HTTP server authentication
[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, attrs);
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, attrs);
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, attrs);
111 } else {
112 res = new DefaultLdapEntry(getDirectory(), name, attrs);
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 + "=" + getDirectory().getUserObjectClass() + ")(" + objectClass + "="
150 + getDirectory().getGroupObjectClass() + "))";
151 SearchControls searchControls = new SearchControls();
152 // FIXME make one level consistent with deep
153 searchControls.setSearchScope(deep ? SearchControls.SUBTREE_SCOPE : SearchControls.ONELEVEL_SCOPE);
154
155 // LdapName searchBase = getBaseDn();
156 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
157
158 results: while (results.hasMoreElements()) {
159 SearchResult searchResult = results.next();
160 Attributes attrs = searchResult.getAttributes();
161 Attribute objectClassAttr = attrs.get(objectClass.name());
162 LdapName dn = toDn(searchBase, searchResult);
163 LdapEntry role;
164 if (objectClassAttr.contains(getDirectory().getGroupObjectClass())
165 || objectClassAttr.contains(getDirectory().getGroupObjectClass().toLowerCase()))
166 role = newGroup(dn, attrs);
167 else if (objectClassAttr.contains(getDirectory().getUserObjectClass())
168 || objectClassAttr.contains(getDirectory().getUserObjectClass().toLowerCase()))
169 role = newUser(dn, attrs);
170 else {
171 // log.warn("Unsupported LDAP type for " + searchResult.getName());
172 continue results;
173 }
174 res.add(role);
175 }
176 return res;
177 } catch (AuthenticationNotSupportedException e) {
178 // ignore (typically an unsupported anonymous bind)
179 // TODO better logging
180 return res;
181 } catch (NamingException e) {
182 throw new IllegalStateException("Cannot get roles for filter " + f, e);
183 }
184 }
185
186 private LdapName toDn(LdapName baseDn, Binding binding) throws InvalidNameException {
187 return new LdapName(binding.isRelative() ? binding.getName() + "," + baseDn : binding.getName());
188 }
189
190 @Override
191 public List<LdapName> getDirectGroups(LdapName dn) {
192 List<LdapName> directGroups = new ArrayList<LdapName>();
193 try {
194 String searchFilter = "(&(" + objectClass + "=" + getDirectory().getGroupObjectClass() + ")("
195 + getDirectory().getMemberAttributeId() + "=" + dn + "))";
196
197 SearchControls searchControls = new SearchControls();
198 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
199
200 LdapName searchBase = getDirectory().getBaseDn();
201 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
202
203 while (results.hasMoreElements()) {
204 SearchResult searchResult = (SearchResult) results.nextElement();
205 directGroups.add(toDn(searchBase, searchResult));
206 }
207 return directGroups;
208 } catch (NamingException e) {
209 throw new IllegalStateException("Cannot populate direct members of " + dn, e);
210 }
211 }
212
213 @Override
214 public void prepare(LdapEntryWorkingCopy wc) {
215 try {
216 ldapConnection.prepareChanges(wc);
217 } catch (NamingException e) {
218 throw new IllegalStateException("Cannot prepare LDAP", e);
219 }
220 }
221
222 @Override
223 public void commit(LdapEntryWorkingCopy wc) {
224 try {
225 ldapConnection.commitChanges(wc);
226 } catch (NamingException e) {
227 throw new IllegalStateException("Cannot commit LDAP", e);
228 }
229 }
230
231 @Override
232 public void rollback(LdapEntryWorkingCopy wc) {
233 // prepare not impacting
234 }
235
236 /*
237 * HIERARCHY
238 */
239
240 @Override
241 public Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
242 List<HierarchyUnit> res = new ArrayList<>();
243 try {
244 String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass
245 + "=" + LdapObjs.organization.name() + "))";
246 // String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass
247 // + "=" + LdapObjs.organization.name() + ")(cn=accounts)(cn=users)(cn=groups))";
248
249 SearchControls searchControls = new SearchControls();
250 searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
251
252 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
253
254 while (results.hasMoreElements()) {
255 SearchResult searchResult = (SearchResult) results.nextElement();
256 LdapName dn = toDn(searchBase, searchResult);
257 Attributes attrs = searchResult.getAttributes();
258 LdapHierarchyUnit hierarchyUnit = new LdapHierarchyUnit(getDirectory(), dn, attrs);
259 if (functionalOnly) {
260 if (hierarchyUnit.isFunctional())
261 res.add(hierarchyUnit);
262 } else {
263 res.add(hierarchyUnit);
264 }
265 }
266 return res;
267 } catch (NamingException e) {
268 throw new IllegalStateException("Cannot get direct hierarchy units ", e);
269 }
270 }
271
272 @Override
273 public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
274 try {
275 if (getDirectory().getBaseDn().equals(dn))
276 return getDirectory();
277 if (!dn.startsWith(getDirectory().getBaseDn()))
278 throw new IllegalArgumentException(dn + " does not start with base DN " + getDirectory().getBaseDn());
279 Attributes attrs = ldapConnection.getAttributes(dn);
280 return new LdapHierarchyUnit(getDirectory(), dn, attrs);
281 } catch (NamingException e) {
282 throw new IllegalStateException("Cannot get hierarchy unit " + dn, e);
283 }
284 }
285
286 }