]> git.argeo.org Git - lgpl/argeo-commons.git/blob - useradmin/LdapUserAdmin.java
Prepare next development cycle
[lgpl/argeo-commons.git] / useradmin / LdapUserAdmin.java
1 package org.argeo.osgi.useradmin;
2
3 import static org.argeo.util.naming.LdapAttrs.objectClass;
4
5 import java.util.ArrayList;
6 import java.util.Dictionary;
7 import java.util.List;
8
9 import javax.naming.AuthenticationNotSupportedException;
10 import javax.naming.Binding;
11 import javax.naming.Context;
12 import javax.naming.InvalidNameException;
13 import javax.naming.NameNotFoundException;
14 import javax.naming.NamingEnumeration;
15 import javax.naming.NamingException;
16 import javax.naming.directory.Attribute;
17 import javax.naming.directory.Attributes;
18 import javax.naming.directory.SearchControls;
19 import javax.naming.directory.SearchResult;
20 import javax.naming.ldap.LdapName;
21
22 import org.argeo.util.naming.LdapObjs;
23 import org.osgi.framework.Filter;
24 import org.osgi.service.useradmin.Role;
25 import org.osgi.service.useradmin.User;
26
27 /** A user admin based on a LDAP server. */
28 public class LdapUserAdmin extends AbstractUserDirectory {
29 private LdapConnection ldapConnection;
30
31 public LdapUserAdmin(Dictionary<String, ?> properties) {
32 this(properties, false);
33 }
34
35 public LdapUserAdmin(Dictionary<String, ?> properties, boolean scoped) {
36 super(null, properties, scoped);
37 ldapConnection = new LdapConnection(getUri().toString(), properties);
38 }
39
40 public void destroy() {
41 ldapConnection.destroy();
42 }
43
44 @Override
45 protected AbstractUserDirectory scope(User user) {
46 Dictionary<String, Object> credentials = user.getCredentials();
47 String username = (String) credentials.get(SHARED_STATE_USERNAME);
48 if (username == null)
49 username = user.getName();
50 Dictionary<String, Object> properties = cloneProperties();
51 properties.put(Context.SECURITY_PRINCIPAL, username.toString());
52 Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
53 byte[] pwd = (byte[]) pwdCred;
54 if (pwd != null) {
55 char[] password = DigestUtils.bytesToChars(pwd);
56 properties.put(Context.SECURITY_CREDENTIALS, new String(password));
57 } else {
58 properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
59 }
60 return new LdapUserAdmin(properties, true);
61 }
62
63 // protected InitialLdapContext getLdapContext() {
64 // return initialLdapContext;
65 // }
66
67 @Override
68 protected Boolean daoHasRole(LdapName dn) {
69 try {
70 return daoGetRole(dn) != null;
71 } catch (NameNotFoundException e) {
72 return false;
73 }
74 }
75
76 @Override
77 protected DirectoryUser daoGetRole(LdapName name) throws NameNotFoundException {
78 try {
79 Attributes attrs = ldapConnection.getAttributes(name);
80 if (attrs.size() == 0)
81 return null;
82 int roleType = roleType(name);
83 DirectoryUser res;
84 if (roleType == Role.GROUP)
85 res = newGroup(name, attrs);
86 else if (roleType == Role.USER)
87 res = newUser(name, attrs);
88 else
89 throw new IllegalArgumentException("Unsupported LDAP type for " + name);
90 return res;
91 } catch (NameNotFoundException e) {
92 throw e;
93 } catch (NamingException e) {
94 return null;
95 }
96 }
97
98 @Override
99 protected List<DirectoryUser> doGetRoles(LdapName searchBase, Filter f, boolean deep) {
100 ArrayList<DirectoryUser> res = new ArrayList<DirectoryUser>();
101 try {
102 String searchFilter = f != null ? f.toString()
103 : "(|(" + objectClass + "=" + getUserObjectClass() + ")(" + objectClass + "="
104 + getGroupObjectClass() + "))";
105 SearchControls searchControls = new SearchControls();
106 // FIXME make one level consistent with deep
107 searchControls.setSearchScope(deep ? SearchControls.SUBTREE_SCOPE : SearchControls.ONELEVEL_SCOPE);
108
109 // LdapName searchBase = getBaseDn();
110 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
111
112 results: while (results.hasMoreElements()) {
113 SearchResult searchResult = results.next();
114 Attributes attrs = searchResult.getAttributes();
115 Attribute objectClassAttr = attrs.get(objectClass.name());
116 LdapName dn = toDn(searchBase, searchResult);
117 DirectoryUser role;
118 if (objectClassAttr.contains(getGroupObjectClass())
119 || objectClassAttr.contains(getGroupObjectClass().toLowerCase()))
120 role = newGroup(dn, attrs);
121 else if (objectClassAttr.contains(getUserObjectClass())
122 || objectClassAttr.contains(getUserObjectClass().toLowerCase()))
123 role = newUser(dn, attrs);
124 else {
125 // log.warn("Unsupported LDAP type for " + searchResult.getName());
126 continue results;
127 }
128 res.add(role);
129 }
130 return res;
131 } catch (AuthenticationNotSupportedException e) {
132 // ignore (typically an unsupported anonymous bind)
133 // TODO better logging
134 return res;
135 } catch (NamingException e) {
136 throw new IllegalStateException("Cannot get roles for filter " + f, e);
137 }
138 }
139
140 private LdapName toDn(LdapName baseDn, Binding binding) throws InvalidNameException {
141 return new LdapName(binding.isRelative() ? binding.getName() + "," + baseDn : binding.getName());
142 }
143
144 @Override
145 protected List<LdapName> getDirectGroups(LdapName dn) {
146 List<LdapName> directGroups = new ArrayList<LdapName>();
147 try {
148 String searchFilter = "(&(" + objectClass + "=" + getGroupObjectClass() + ")(" + getMemberAttributeId()
149 + "=" + dn + "))";
150
151 SearchControls searchControls = new SearchControls();
152 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
153
154 LdapName searchBase = getBaseDn();
155 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
156
157 while (results.hasMoreElements()) {
158 SearchResult searchResult = (SearchResult) results.nextElement();
159 directGroups.add(toDn(searchBase, searchResult));
160 }
161 return directGroups;
162 } catch (NamingException e) {
163 throw new IllegalStateException("Cannot populate direct members of " + dn, e);
164 }
165 }
166
167 @Override
168 protected void prepare(UserDirectoryWorkingCopy wc) {
169 try {
170 ldapConnection.prepareChanges(wc);
171 } catch (NamingException e) {
172 throw new IllegalStateException("Cannot prepare LDAP", e);
173 }
174 }
175
176 @Override
177 protected void commit(UserDirectoryWorkingCopy wc) {
178 try {
179 ldapConnection.commitChanges(wc);
180 } catch (NamingException e) {
181 throw new IllegalStateException("Cannot commit LDAP", e);
182 }
183 }
184
185 @Override
186 protected void rollback(UserDirectoryWorkingCopy wc) {
187 // prepare not impacting
188 }
189
190 /*
191 * HIERARCHY
192 */
193
194 @Override
195 protected Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) {
196 List<HierarchyUnit> res = new ArrayList<>();
197 try {
198 String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass
199 + "=" + LdapObjs.organization.name() + "))";
200
201 SearchControls searchControls = new SearchControls();
202 searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
203
204 NamingEnumeration<SearchResult> results = ldapConnection.search(searchBase, searchFilter, searchControls);
205
206 while (results.hasMoreElements()) {
207 SearchResult searchResult = (SearchResult) results.nextElement();
208 LdapName dn = toDn(searchBase, searchResult);
209 Attributes attrs = searchResult.getAttributes();
210 LdifHierarchyUnit hierarchyUnit = new LdifHierarchyUnit(this, dn, attrs);
211 if (functionalOnly) {
212 if (hierarchyUnit.isFunctional())
213 res.add(hierarchyUnit);
214 } else {
215 res.add(hierarchyUnit);
216 }
217 }
218 return res;
219 } catch (NamingException e) {
220 throw new IllegalStateException("Cannot get direct hierarchy units ", e);
221 }
222 }
223
224 @Override
225 protected HierarchyUnit doGetHierarchyUnit(LdapName dn) {
226 try {
227 Attributes attrs = ldapConnection.getAttributes(dn);
228 return new LdifHierarchyUnit(this, dn, attrs);
229 } catch (NamingException e) {
230 throw new IllegalStateException("Cannot get hierarchy unit " + dn, e);
231 }
232 }
233
234 }