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