]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java
c5ca49300425ad2910d361b2253c9e5728d7de35
[lgpl/argeo-commons.git] / org.argeo.security.core / src / org / argeo / osgi / useradmin / LdifUserAdmin.java
1 package org.argeo.osgi.useradmin;
2
3 import java.io.File;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.OutputStream;
8 import java.net.URI;
9 import java.net.URISyntaxException;
10 import java.util.ArrayList;
11 import java.util.Dictionary;
12 import java.util.LinkedHashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.SortedMap;
16 import java.util.TreeMap;
17
18 import javax.naming.InvalidNameException;
19 import javax.naming.NamingEnumeration;
20 import javax.naming.directory.Attributes;
21 import javax.naming.directory.BasicAttributes;
22 import javax.naming.ldap.LdapName;
23 import javax.naming.ldap.Rdn;
24
25 import org.apache.commons.io.IOUtils;
26 import org.osgi.framework.Filter;
27 import org.osgi.framework.FrameworkUtil;
28 import org.osgi.framework.InvalidSyntaxException;
29 import org.osgi.service.useradmin.Authorization;
30 import org.osgi.service.useradmin.Role;
31 import org.osgi.service.useradmin.User;
32
33 /** User admin implementation using LDIF file(s) as backend. */
34 public class LdifUserAdmin extends AbstractLdapUserAdmin {
35 SortedMap<LdapName, LdifUser> users = new TreeMap<LdapName, LdifUser>();
36 SortedMap<LdapName, LdifGroup> groups = new TreeMap<LdapName, LdifGroup>();
37
38 private Map<String, Map<String, LdifUser>> userIndexes = new LinkedHashMap<String, Map<String, LdifUser>>();
39
40 // private Map<LdapName, List<LdifGroup>> directMemberOf = new
41 // TreeMap<LdapName, List<LdifGroup>>();
42
43 public LdifUserAdmin(String uri) {
44 this(uri, true);
45 }
46
47 public LdifUserAdmin(String uri, boolean isReadOnly) {
48 setReadOnly(isReadOnly);
49 try {
50 setUri(new URI(uri));
51 } catch (URISyntaxException e) {
52 throw new ArgeoUserAdminException("Invalid URI " + uri, e);
53 }
54
55 if (!isReadOnly && !getUri().getScheme().equals("file:"))
56 throw new UnsupportedOperationException(getUri().getScheme()
57 + "not supported read-write.");
58
59 }
60
61 public LdifUserAdmin(InputStream in) {
62 load(in);
63 setReadOnly(true);
64 setUri(null);
65 }
66
67 public void init() {
68 try {
69 load(getUri().toURL().openStream());
70 } catch (Exception e) {
71 throw new ArgeoUserAdminException("Cannot open URL " + getUri(), e);
72 }
73 }
74
75 public void save() {
76 if (getUri() == null || isReadOnly())
77 throw new ArgeoUserAdminException("Cannot save LDIF user admin");
78 try (FileOutputStream out = new FileOutputStream(new File(getUri()))) {
79 save(out);
80 } catch (IOException e) {
81 throw new ArgeoUserAdminException("Cannot save user admin to "
82 + getUri(), e);
83 }
84 }
85
86 public void save(OutputStream out) throws IOException {
87 try {
88 LdifWriter ldifWriter = new LdifWriter(out);
89 for (LdapName name : groups.keySet())
90 ldifWriter.writeEntry(name, groups.get(name).getAttributes());
91 for (LdapName name : users.keySet())
92 ldifWriter.writeEntry(name, users.get(name).getAttributes());
93 } finally {
94 IOUtils.closeQuietly(out);
95 }
96 }
97
98 protected void load(InputStream in) {
99 try {
100 LdifParser ldifParser = new LdifParser();
101 SortedMap<LdapName, Attributes> allEntries = ldifParser.read(in);
102 for (LdapName key : allEntries.keySet()) {
103 Attributes attributes = allEntries.get(key);
104 NamingEnumeration<?> objectClasses = attributes.get(
105 "objectClass").getAll();
106 objectClasses: while (objectClasses.hasMore()) {
107 String objectClass = objectClasses.next().toString();
108 if (objectClass.equals("inetOrgPerson")) {
109 users.put(key, new LdifUser(key, attributes));
110 break objectClasses;
111 } else if (objectClass.equals("groupOfNames")) {
112 groups.put(key, new LdifGroup(this, key, attributes));
113 break objectClasses;
114 }
115 }
116 }
117
118 // optimise
119 // for (LdifGroup group : groups.values())
120 // loadMembers(group);
121
122 // indexes
123 for (String attr : getIndexedUserProperties())
124 userIndexes.put(attr, new TreeMap<String, LdifUser>());
125
126 for (LdifUser user : users.values()) {
127 Dictionary<String, Object> properties = user.getProperties();
128 for (String attr : getIndexedUserProperties()) {
129 Object value = properties.get(attr);
130 if (value != null) {
131 LdifUser otherUser = userIndexes.get(attr).put(
132 value.toString(), user);
133 if (otherUser != null)
134 throw new ArgeoUserAdminException("User " + user
135 + " and user " + otherUser
136 + " both have property " + attr
137 + " set to " + value);
138 }
139 }
140 }
141 } catch (Exception e) {
142 throw new ArgeoUserAdminException(
143 "Cannot load user admin service from LDIF", e);
144 }
145 }
146
147 public void destroy() {
148 users.clear();
149 users = null;
150 groups.clear();
151 groups = null;
152 }
153
154 @Override
155 public Role getRole(String name) {
156 LdapName key;
157 try {
158 key = new LdapName(name);
159 } catch (InvalidNameException e) {
160 // TODO implements default base DN
161 throw new IllegalArgumentException("Badly formatted role name: "
162 + name, e);
163 }
164
165 if (groups.containsKey(key))
166 return groups.get(key);
167 if (users.containsKey(key))
168 return users.get(key);
169 return null;
170 }
171
172 @Override
173 public Authorization getAuthorization(User user) {
174 return new LdifAuthorization((LdifUser) user,
175 getAllRoles((LdifUser) user));
176 }
177
178 @Override
179 public Role createRole(String name, int type) {
180 try {
181 LdapName dn = new LdapName(name);
182 if (users.containsKey(dn) || groups.containsKey(dn))
183 throw new ArgeoUserAdminException("Already a role " + name);
184
185 BasicAttributes attrs = new BasicAttributes();
186 attrs.put("dn", dn.toString());
187 Rdn nameRdn = dn.getRdn(dn.size() - 1);
188 // TODO deal with multiple attr RDN
189 attrs.put(nameRdn.getType(), nameRdn.getValue());
190 LdifUser newRole;
191 if (type == Role.USER) {
192 newRole = new LdifUser(dn, attrs);
193 users.put(dn, newRole);
194 } else if (type == Role.GROUP) {
195 newRole = new LdifGroup(this, dn, attrs);
196 groups.put(dn, (LdifGroup) newRole);
197 } else
198 throw new ArgeoUserAdminException("Unsupported type " + type);
199 return newRole;
200 } catch (InvalidNameException e) {
201 throw new ArgeoUserAdminException("Cannot create role " + name, e);
202 }
203 }
204
205 @Override
206 public boolean removeRole(String name) {
207 try {
208 LdapName dn = new LdapName(name);
209 LdifUser role = null;
210 if (users.containsKey(dn))
211 role = users.remove(dn);
212 else if (groups.containsKey(dn))
213 role = groups.remove(dn);
214 else
215 throw new ArgeoUserAdminException("There is no role " + name);
216 if (role == null)
217 return false;
218 for (LdifGroup group : getDirectGroups(role)) {
219 // group.directMembers.remove(role);
220 group.getAttributes().get(group.getMemberAttrName())
221 .remove(dn.toString());
222 }
223 if (role instanceof LdifGroup) {
224 LdifGroup group = (LdifGroup) role;
225 // for (Role user : group.directMembers) {
226 // if (user instanceof LdifUser)
227 // directMemberOf.get(((LdifUser) user).getDn()).remove(
228 // group);
229 // }
230 }
231 return true;
232 } catch (InvalidNameException e) {
233 throw new ArgeoUserAdminException("Cannot create role " + name, e);
234 }
235 }
236
237 @Override
238 public Role[] getRoles(String filter) throws InvalidSyntaxException {
239 ArrayList<Role> res = new ArrayList<Role>();
240 if (filter == null) {
241 res.addAll(users.values());
242 res.addAll(groups.values());
243 } else {
244 Filter f = FrameworkUtil.createFilter(filter);
245 for (LdifUser user : users.values())
246 if (f.match(user.getProperties()))
247 res.add(user);
248 for (LdifUser group : groups.values())
249 if (f.match(group.getProperties()))
250 res.add(group);
251 }
252 return res.toArray(new Role[res.size()]);
253 }
254
255 @Override
256 public User getUser(String key, String value) {
257 // TODO check value null or empty
258 if (key != null) {
259 if (!userIndexes.containsKey(key))
260 return null;
261 return userIndexes.get(key).get(value);
262 }
263
264 // Try all indexes
265 List<LdifUser> collectedUsers = new ArrayList<LdifUser>(
266 getIndexedUserProperties().size());
267 // try dn
268 LdifUser user = null;
269 try {
270 user = (LdifUser) getRole(value);
271 if (user != null)
272 collectedUsers.add(user);
273 } catch (Exception e) {
274 // silent
275 }
276 for (String attr : userIndexes.keySet()) {
277 user = userIndexes.get(attr).get(value);
278 if (user != null)
279 collectedUsers.add(user);
280 }
281
282 if (collectedUsers.size() == 1)
283 return collectedUsers.get(0);
284 return null;
285 // throw new UnsupportedOperationException();
286 }
287
288 // protected void loadMembers(LdifGroup group) {
289 // group.directMembers = new ArrayList<Role>();
290 // for (LdapName ldapName : group.getMemberNames()) {
291 // LdifUser role = null;
292 // if (groups.containsKey(ldapName))
293 // role = groups.get(ldapName);
294 // else if (users.containsKey(ldapName))
295 // role = users.get(ldapName);
296 // else {
297 // if (getExternalRoles() != null)
298 // role = (LdifUser) getExternalRoles().getRole(
299 // ldapName.toString());
300 // if (role == null)
301 // throw new ArgeoUserAdminException("No role found for "
302 // + ldapName);
303 // }
304 // // role.directMemberOf.add(group);
305 // // if (!directMemberOf.containsKey(role.getDn()))
306 // // directMemberOf.put(role.getDn(), new ArrayList<LdifGroup>());
307 // // directMemberOf.get(role.getDn()).add(group);
308 // group.directMembers.add(role);
309 // }
310 // }
311
312 @Override
313 protected List<LdifGroup> getDirectGroups(User user) {
314 LdapName dn;
315 if (user instanceof LdifUser)
316 dn = ((LdifUser) user).getDn();
317 else
318 try {
319 dn = new LdapName(user.getName());
320 } catch (InvalidNameException e) {
321 throw new ArgeoUserAdminException("Badly formatted user name "
322 + user.getName(), e);
323 }
324
325 List<LdifGroup> directGroups = new ArrayList<LdifGroup>();
326 for (LdapName name : groups.keySet()) {
327 LdifGroup group = groups.get(name);
328 if (group.getMemberNames().contains(dn))
329 directGroups.add(group);
330 }
331 return directGroups;
332 // if (directMemberOf.containsKey(dn))
333 // return Collections.unmodifiableList(directMemberOf.get(dn));
334 // else
335 // return Collections.EMPTY_LIST;
336 }
337
338 }