]> git.argeo.org Git - lgpl/argeo-commons.git/blob - useradmin/LdifUserAdmin.java
Prepare next development cycle
[lgpl/argeo-commons.git] / 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.util.ArrayList;
9 import java.util.Dictionary;
10 import java.util.Hashtable;
11 import java.util.LinkedHashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.SortedMap;
15 import java.util.TreeMap;
16
17 import javax.naming.InvalidNameException;
18 import javax.naming.NamingEnumeration;
19 import javax.naming.directory.Attributes;
20 import javax.naming.ldap.LdapName;
21
22 import org.apache.commons.io.IOUtils;
23 import org.osgi.framework.Filter;
24 import org.osgi.service.useradmin.Role;
25 import org.osgi.service.useradmin.User;
26
27 /** User admin implementation using LDIF file(s) as backend. */
28 public class LdifUserAdmin extends AbstractUserDirectory {
29 SortedMap<LdapName, DirectoryUser> users = new TreeMap<LdapName, DirectoryUser>();
30 SortedMap<LdapName, DirectoryGroup> groups = new TreeMap<LdapName, DirectoryGroup>();
31
32 private Map<String, Map<String, DirectoryUser>> userIndexes = new LinkedHashMap<String, Map<String, DirectoryUser>>();
33
34 public LdifUserAdmin(String uri, String baseDn) {
35 this(fromUri(uri, baseDn));
36 }
37
38 public LdifUserAdmin(Dictionary<String, ?> properties) {
39 super(properties);
40 }
41
42 public LdifUserAdmin(InputStream in) {
43 super(new Hashtable<String, Object>());
44 load(in);
45 setReadOnly(true);
46 setUri(null);
47 }
48
49 private static Dictionary<String, Object> fromUri(String uri, String baseDn) {
50 Hashtable<String, Object> res = new Hashtable<String, Object>();
51 res.put(UserAdminProps.uri.property(), uri);
52 res.put(UserAdminProps.baseDn.property(), baseDn);
53 return res;
54 }
55
56 public void init() {
57 try {
58 if (getUri().getScheme().equals("file")) {
59 File file = new File(getUri());
60 if (!file.exists())
61 return;
62 }
63 load(getUri().toURL().openStream());
64 } catch (Exception e) {
65 throw new UserDirectoryException("Cannot open URL " + getUri(), e);
66 }
67 }
68
69 public void save() {
70 if (getUri() == null || isReadOnly())
71 throw new UserDirectoryException("Cannot save LDIF user admin");
72 try (FileOutputStream out = new FileOutputStream(new File(getUri()))) {
73 save(out);
74 } catch (IOException e) {
75 throw new UserDirectoryException("Cannot save user admin to "
76 + getUri(), e);
77 }
78 }
79
80 public void save(OutputStream out) throws IOException {
81 try {
82 LdifWriter ldifWriter = new LdifWriter(out);
83 for (LdapName name : groups.keySet())
84 ldifWriter.writeEntry(name, groups.get(name).getAttributes());
85 for (LdapName name : users.keySet())
86 ldifWriter.writeEntry(name, users.get(name).getAttributes());
87 } finally {
88 IOUtils.closeQuietly(out);
89 }
90 }
91
92 @SuppressWarnings("unchecked")
93 protected void load(InputStream in) {
94 try {
95 users.clear();
96 groups.clear();
97
98 LdifParser ldifParser = new LdifParser();
99 SortedMap<LdapName, Attributes> allEntries = ldifParser.read(in);
100 for (LdapName key : allEntries.keySet()) {
101 Attributes attributes = allEntries.get(key);
102 NamingEnumeration<?> objectClasses = attributes.get(
103 "objectClass").getAll();
104 objectClasses: while (objectClasses.hasMore()) {
105 String objectClass = objectClasses.next().toString();
106 if (objectClass.equals("inetOrgPerson")) {
107 users.put(key, new LdifUser(this, key, attributes));
108 break objectClasses;
109 } else if (objectClass.equals("groupOfNames")) {
110 groups.put(key, new LdifGroup(this, key, attributes));
111 break objectClasses;
112 }
113 }
114 }
115
116 // indexes
117 for (String attr : getIndexedUserProperties())
118 userIndexes.put(attr, new TreeMap<String, DirectoryUser>());
119
120 for (DirectoryUser user : users.values()) {
121 Dictionary<String, ?> properties = user.getProperties();
122 for (String attr : getIndexedUserProperties()) {
123 Object value = properties.get(attr);
124 if (value != null) {
125 DirectoryUser otherUser = userIndexes.get(attr).put(
126 value.toString(), user);
127 if (otherUser != null)
128 throw new UserDirectoryException("User " + user
129 + " and user " + otherUser
130 + " both have property " + attr
131 + " set to " + value);
132 }
133 }
134 }
135 } catch (Exception e) {
136 throw new UserDirectoryException(
137 "Cannot load user admin service from LDIF", e);
138 }
139 }
140
141 public void destroy() {
142 users.clear();
143 users = null;
144 groups.clear();
145 groups = null;
146 }
147
148 protected DirectoryUser daoGetRole(LdapName key) {
149 if (groups.containsKey(key))
150 return groups.get(key);
151 if (users.containsKey(key))
152 return users.get(key);
153 return null;
154 }
155
156 protected Boolean daoHasRole(LdapName dn) {
157 return users.containsKey(dn) || groups.containsKey(dn);
158 }
159
160 @SuppressWarnings("unchecked")
161 protected List<DirectoryUser> doGetRoles(Filter f) {
162 ArrayList<DirectoryUser> res = new ArrayList<DirectoryUser>();
163 if (f == null) {
164 res.addAll(users.values());
165 res.addAll(groups.values());
166 } else {
167 // Filter f = FrameworkUtil.createFilter(filter);
168 for (DirectoryUser user : users.values())
169 if (f.match(user.getProperties()))
170 res.add(user);
171 for (DirectoryUser group : groups.values())
172 if (f.match(group.getProperties()))
173 res.add(group);
174 }
175 return res;
176 }
177
178 protected void doGetUser(String key, String value,
179 List<DirectoryUser> collectedUsers) {
180 assert key != null;
181 DirectoryUser user = userIndexes.get(key).get(value);
182 if (user != null)
183 collectedUsers.add(user);
184 }
185
186 @Override
187 protected List<DirectoryGroup> getDirectGroups(User user) {
188 LdapName dn;
189 if (user instanceof LdifUser)
190 dn = ((LdifUser) user).getDn();
191 else
192 try {
193 dn = new LdapName(user.getName());
194 } catch (InvalidNameException e) {
195 throw new UserDirectoryException("Badly formatted user name "
196 + user.getName(), e);
197 }
198
199 List<DirectoryGroup> directGroups = new ArrayList<DirectoryGroup>();
200 for (LdapName name : groups.keySet()) {
201 DirectoryGroup group = groups.get(name);
202 if (group.getMemberNames().contains(dn))
203 directGroups.add(group);
204 }
205 return directGroups;
206 }
207
208 @Override
209 protected void prepare(WorkingCopy wc) {
210 // delete
211 for (LdapName dn : wc.getDeletedUsers().keySet()) {
212 if (users.containsKey(dn))
213 users.remove(dn);
214 else if (groups.containsKey(dn))
215 groups.remove(dn);
216 else
217 throw new UserDirectoryException("User to delete no found "
218 + dn);
219 }
220 // add
221 for (LdapName dn : wc.getNewUsers().keySet()) {
222 DirectoryUser user = wc.getNewUsers().get(dn);
223 if (Role.USER == user.getType())
224 users.put(dn, user);
225 else if (Role.GROUP == user.getType())
226 groups.put(dn, (DirectoryGroup) user);
227 else
228 throw new UserDirectoryException("Unsupported role type "
229 + user.getType() + " for new user " + dn);
230 }
231 // modify
232 for (LdapName dn : wc.getModifiedUsers().keySet()) {
233 Attributes modifiedAttrs = wc.getModifiedUsers().get(dn);
234 DirectoryUser user;
235 if (users.containsKey(dn))
236 user = users.get(dn);
237 else if (groups.containsKey(dn))
238 user = groups.get(dn);
239 else
240 throw new UserDirectoryException("User to modify no found "
241 + dn);
242 user.publishAttributes(modifiedAttrs);
243 }
244 }
245
246 @Override
247 protected void commit(WorkingCopy wc) {
248 save();
249 }
250
251 @Override
252 protected void rollback(WorkingCopy wc) {
253 init();
254 }
255
256 }