]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java
Make LDIF importable
[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.InputStream;
4 import java.net.URI;
5 import java.net.URISyntaxException;
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Dictionary;
9 import java.util.LinkedHashMap;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.SortedMap;
13 import java.util.TreeMap;
14
15 import javax.naming.InvalidNameException;
16 import javax.naming.NamingEnumeration;
17 import javax.naming.directory.Attributes;
18 import javax.naming.ldap.LdapName;
19
20 import org.osgi.framework.InvalidSyntaxException;
21 import org.osgi.service.useradmin.Authorization;
22 import org.osgi.service.useradmin.Role;
23 import org.osgi.service.useradmin.User;
24 import org.osgi.service.useradmin.UserAdmin;
25
26 /** User admin implementation using LDIF file(s) as backend. */
27 public class LdifUserAdmin implements UserAdmin {
28 SortedMap<LdapName, LdifUser> users = new TreeMap<LdapName, LdifUser>();
29 SortedMap<LdapName, LdifGroup> groups = new TreeMap<LdapName, LdifGroup>();
30
31 private final boolean isReadOnly;
32 private final URI uri;
33
34 private List<String> indexedUserProperties = Arrays.asList(new String[] {
35 "uid", "mail", "cn" });
36 private Map<String, Map<String, LdifUser>> userIndexes = new LinkedHashMap<String, Map<String, LdifUser>>();
37
38 public LdifUserAdmin(String uri) {
39 this(uri, true);
40 }
41
42 public LdifUserAdmin(String uri, boolean isReadOnly) {
43 this.isReadOnly = isReadOnly;
44 try {
45 this.uri = new URI(uri);
46 } catch (URISyntaxException e) {
47 throw new ArgeoUserAdminException("Invalid URI " + uri, e);
48 }
49
50 if (!isReadOnly && !this.uri.getScheme().equals("file:"))
51 throw new UnsupportedOperationException(this.uri.getScheme()
52 + "not supported read-write.");
53
54 try {
55 load(this.uri.toURL().openStream());
56 } catch (Exception e) {
57 throw new ArgeoUserAdminException("Cannot open URL " + this.uri, e);
58 }
59 }
60
61 public LdifUserAdmin(InputStream in) {
62 load(in);
63 isReadOnly = true;
64 this.uri = null;
65 }
66
67 protected void load(InputStream in) {
68 try {
69 LdifParser ldifParser = new LdifParser();
70 SortedMap<LdapName, Attributes> allEntries = ldifParser.read(in);
71 for (LdapName key : allEntries.keySet()) {
72 Attributes attributes = allEntries.get(key);
73 NamingEnumeration<?> objectClasses = attributes.get(
74 "objectClass").getAll();
75 objectClasses: while (objectClasses.hasMore()) {
76 String objectClass = objectClasses.next().toString();
77 if (objectClass.equals("inetOrgPerson")) {
78 users.put(key, new LdifUser(key, attributes));
79 break objectClasses;
80 } else if (objectClass.equals("groupOfNames")) {
81 groups.put(key, new LdifGroup(key, attributes));
82 break objectClasses;
83 }
84 }
85 }
86
87 // optimise
88 for (LdifGroup group : groups.values())
89 group.loadMembers(this);
90
91 // indexes
92 for (String attr : indexedUserProperties)
93 userIndexes.put(attr, new TreeMap<String, LdifUser>());
94
95 for (LdifUser user : users.values()) {
96 Dictionary<String, Object> properties = user.getProperties();
97 for (String attr : indexedUserProperties) {
98 Object value = properties.get(attr);
99 if (value != null) {
100 LdifUser otherUser = userIndexes.get(attr).put(
101 value.toString(), user);
102 if (otherUser != null)
103 throw new ArgeoUserAdminException("User " + user
104 + " and user " + otherUser
105 + " both habe property " + attr
106 + " set to " + value);
107 }
108 }
109 }
110 } catch (Exception e) {
111 throw new ArgeoUserAdminException(
112 "Cannot load user admin service from LDIF", e);
113 }
114 }
115
116 public void destroy() {
117 users.clear();
118 users = null;
119 groups.clear();
120 groups = null;
121 }
122
123 @Override
124 public Role getRole(String name) {
125 LdapName key;
126 try {
127 key = new LdapName(name);
128 } catch (InvalidNameException e) {
129 // TODO implements default base DN
130 throw new IllegalArgumentException("Badly formatted role name: "
131 + name, e);
132 }
133
134 if (groups.containsKey(key))
135 return groups.get(key);
136 if (users.containsKey(key))
137 return users.get(key);
138 return null;
139 }
140
141 @Override
142 public Authorization getAuthorization(User user) {
143 return new LdifAuthorization((LdifUser) user);
144 }
145
146 @Override
147 public Role createRole(String name, int type) {
148 throw new UnsupportedOperationException();
149 }
150
151 @Override
152 public boolean removeRole(String name) {
153 throw new UnsupportedOperationException();
154 }
155
156 @Override
157 public Role[] getRoles(String filter) throws InvalidSyntaxException {
158 throw new UnsupportedOperationException();
159 }
160
161 @Override
162 public User getUser(String key, String value) {
163 // TODO check value null or empty
164 if (key != null) {
165 if (!userIndexes.containsKey(key))
166 return null;
167 return userIndexes.get(key).get(value);
168 }
169
170 // Try all indexes
171 List<LdifUser> collectedUsers = new ArrayList<LdifUser>(
172 indexedUserProperties.size());
173 // try dn
174 LdifUser user = null;
175 try {
176 user = (LdifUser) getRole(value);
177 if (user != null)
178 collectedUsers.add(user);
179 } catch (Exception e) {
180 // silent
181 }
182 for (String attr : userIndexes.keySet()) {
183 user = userIndexes.get(attr).get(value);
184 if (user != null)
185 collectedUsers.add(user);
186 }
187
188 if (collectedUsers.size() == 1)
189 return collectedUsers.get(0);
190 return null;
191 // throw new UnsupportedOperationException();
192 }
193
194 public boolean getIsReadOnly() {
195 return isReadOnly;
196 }
197
198 }