]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.enterprise/src/org/argeo/osgi/useradmin/LdifUserAdmin.java
Factorize 'node' URI scheme constant.
[lgpl/argeo-commons.git] / org.argeo.enterprise / src / org / argeo / osgi / useradmin / LdifUserAdmin.java
1 package org.argeo.osgi.useradmin;
2
3 import static org.argeo.naming.LdapAttrs.objectClass;
4 import static org.argeo.naming.LdapObjs.inetOrgPerson;
5
6 import java.io.File;
7 import java.io.FileOutputStream;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.OutputStream;
11 import java.util.ArrayList;
12 import java.util.Dictionary;
13 import java.util.HashSet;
14 import java.util.Hashtable;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.SortedMap;
18 import java.util.TreeMap;
19
20 import javax.naming.NamingEnumeration;
21 import javax.naming.directory.Attributes;
22 import javax.naming.ldap.LdapName;
23 import javax.transaction.TransactionManager;
24
25 import org.argeo.naming.LdifParser;
26 import org.argeo.naming.LdifWriter;
27 import org.osgi.framework.Filter;
28 import org.osgi.service.useradmin.Role;
29 import org.osgi.service.useradmin.User;
30
31 /**
32 * A user admin based on a LDIF files. Requires a {@link TransactionManager} and
33 * an open transaction for write access.
34 */
35 public class LdifUserAdmin extends AbstractUserDirectory {
36 private SortedMap<LdapName, DirectoryUser> users = new TreeMap<LdapName, DirectoryUser>();
37 private SortedMap<LdapName, DirectoryGroup> groups = new TreeMap<LdapName, DirectoryGroup>();
38
39 public LdifUserAdmin(String uri, String baseDn) {
40 this(fromUri(uri, baseDn));
41 }
42
43 public LdifUserAdmin(Dictionary<String, ?> properties) {
44 super(properties);
45 }
46
47 public LdifUserAdmin(InputStream in) {
48 super(new Hashtable<String, Object>());
49 load(in);
50 }
51
52 @Override
53 protected AbstractUserDirectory scope(User user) {
54 Dictionary<String, Object> properties = cloneProperties();
55 properties.put(UserAdminConf.readOnly.name(), "true");
56 return new LdifUserAdmin(properties);
57 }
58
59 private static Dictionary<String, Object> fromUri(String uri, String baseDn) {
60 Hashtable<String, Object> res = new Hashtable<String, Object>();
61 res.put(UserAdminConf.uri.name(), uri);
62 res.put(UserAdminConf.baseDn.name(), baseDn);
63 return res;
64 }
65
66 public void init() {
67 try {
68 if (getUri().getScheme().equals("file")) {
69 File file = new File(getUri());
70 if (!file.exists())
71 return;
72 }
73 load(getUri().toURL().openStream());
74 } catch (Exception e) {
75 throw new UserDirectoryException("Cannot open URL " + getUri(), e);
76 }
77 }
78
79 public void save() {
80 if (getUri() == null)
81 throw new UserDirectoryException("Cannot save LDIF user admin: no URI is set");
82 if (isReadOnly())
83 throw new UserDirectoryException("Cannot save LDIF user admin: " + getUri() + " is read-only");
84 try (FileOutputStream out = new FileOutputStream(new File(getUri()))) {
85 save(out);
86 } catch (IOException e) {
87 throw new UserDirectoryException("Cannot save user admin to " + getUri(), e);
88 }
89 }
90
91 public void save(OutputStream out) throws IOException {
92 try {
93 LdifWriter ldifWriter = new LdifWriter(out);
94 for (LdapName name : groups.keySet())
95 ldifWriter.writeEntry(name, groups.get(name).getAttributes());
96 for (LdapName name : users.keySet())
97 ldifWriter.writeEntry(name, users.get(name).getAttributes());
98 } finally {
99 out.close();
100 }
101 }
102
103 protected void load(InputStream in) {
104 try {
105 users.clear();
106 groups.clear();
107
108 LdifParser ldifParser = new LdifParser();
109 SortedMap<LdapName, Attributes> allEntries = ldifParser.read(in);
110 for (LdapName key : allEntries.keySet()) {
111 Attributes attributes = allEntries.get(key);
112 // check for inconsistency
113 Set<String> lowerCase = new HashSet<String>();
114 NamingEnumeration<String> ids = attributes.getIDs();
115 while (ids.hasMoreElements()) {
116 String id = ids.nextElement().toLowerCase();
117 if (lowerCase.contains(id))
118 throw new UserDirectoryException(key + " has duplicate id " + id);
119 lowerCase.add(id);
120 }
121
122 // analyse object classes
123 NamingEnumeration<?> objectClasses = attributes.get(objectClass.name()).getAll();
124 // System.out.println(key);
125 objectClasses: while (objectClasses.hasMore()) {
126 String objectClass = objectClasses.next().toString();
127 // System.out.println(" " + objectClass);
128 if (objectClass.equals(inetOrgPerson.name())) {
129 users.put(key, new LdifUser(this, key, attributes));
130 break objectClasses;
131 } else if (objectClass.equals(getGroupObjectClass())) {
132 groups.put(key, new LdifGroup(this, key, attributes));
133 break objectClasses;
134 }
135 }
136 }
137 } catch (Exception e) {
138 throw new UserDirectoryException("Cannot load user admin service from LDIF", e);
139 }
140 }
141
142 public void destroy() {
143 if (users == null || groups == null)
144 throw new UserDirectoryException("User directory " + getBaseDn() + " is already destroyed");
145 users.clear();
146 users = null;
147 groups.clear();
148 groups = null;
149 }
150
151 protected DirectoryUser daoGetRole(LdapName key) {
152 if (groups.containsKey(key))
153 return groups.get(key);
154 if (users.containsKey(key))
155 return users.get(key);
156 return null;
157 }
158
159 protected Boolean daoHasRole(LdapName dn) {
160 return users.containsKey(dn) || groups.containsKey(dn);
161 }
162
163 @SuppressWarnings("unchecked")
164 protected List<DirectoryUser> doGetRoles(Filter f) {
165 ArrayList<DirectoryUser> res = new ArrayList<DirectoryUser>();
166 if (f == null) {
167 res.addAll(users.values());
168 res.addAll(groups.values());
169 } else {
170 for (DirectoryUser user : users.values()) {
171 // System.out.println("\n" + user.getName());
172 // Dictionary<String, Object> props = user.getProperties();
173 // for (Enumeration<String> keys = props.keys(); keys
174 // .hasMoreElements();) {
175 // String key = keys.nextElement();
176 // System.out.println(" " + key + "=" + props.get(key));
177 // }
178 if (f.match(user.getProperties()))
179 res.add(user);
180 }
181 for (DirectoryUser group : groups.values())
182 if (f.match(group.getProperties()))
183 res.add(group);
184 }
185 return res;
186 }
187
188 @Override
189 protected List<LdapName> getDirectGroups(LdapName dn) {
190 List<LdapName> directGroups = new ArrayList<LdapName>();
191 for (LdapName name : groups.keySet()) {
192 DirectoryGroup group = groups.get(name);
193 if (group.getMemberNames().contains(dn))
194 directGroups.add(group.getDn());
195 }
196 return directGroups;
197 }
198
199 @Override
200 protected void prepare(UserDirectoryWorkingCopy wc) {
201 // delete
202 for (LdapName dn : wc.getDeletedUsers().keySet()) {
203 if (users.containsKey(dn))
204 users.remove(dn);
205 else if (groups.containsKey(dn))
206 groups.remove(dn);
207 else
208 throw new UserDirectoryException("User to delete not found " + dn);
209 }
210 // add
211 for (LdapName dn : wc.getNewUsers().keySet()) {
212 DirectoryUser user = wc.getNewUsers().get(dn);
213 if (users.containsKey(dn) || groups.containsKey(dn))
214 throw new UserDirectoryException("User to create found " + dn);
215 else if (Role.USER == user.getType())
216 users.put(dn, user);
217 else if (Role.GROUP == user.getType())
218 groups.put(dn, (DirectoryGroup) user);
219 else
220 throw new UserDirectoryException("Unsupported role type " + user.getType() + " for new user " + dn);
221 }
222 // modify
223 for (LdapName dn : wc.getModifiedUsers().keySet()) {
224 Attributes modifiedAttrs = wc.getModifiedUsers().get(dn);
225 DirectoryUser user;
226 if (users.containsKey(dn))
227 user = users.get(dn);
228 else if (groups.containsKey(dn))
229 user = groups.get(dn);
230 else
231 throw new UserDirectoryException("User to modify no found " + dn);
232 user.publishAttributes(modifiedAttrs);
233 }
234 }
235
236 @Override
237 protected void commit(UserDirectoryWorkingCopy wc) {
238 save();
239 }
240
241 @Override
242 protected void rollback(UserDirectoryWorkingCopy wc) {
243 init();
244 }
245
246 }