]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUser.java
712ccdfde9eb4848b1ea5477b41542b938b75f0a
[lgpl/argeo-commons.git] / org.argeo.security.core / src / org / argeo / osgi / useradmin / LdifUser.java
1 package org.argeo.osgi.useradmin;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collections;
6 import java.util.Dictionary;
7 import java.util.Enumeration;
8 import java.util.Iterator;
9 import java.util.List;
10
11 import javax.naming.NamingEnumeration;
12 import javax.naming.NamingException;
13 import javax.naming.directory.Attribute;
14 import javax.naming.directory.Attributes;
15 import javax.naming.directory.BasicAttribute;
16 import javax.naming.ldap.LdapName;
17
18 import org.argeo.osgi.useradmin.AbstractUserDirectory.WorkingCopy;
19
20 class LdifUser implements DirectoryUser {
21 private final AbstractUserDirectory userAdmin;
22
23 private final LdapName dn;
24
25 private final boolean frozen;
26 private Attributes publishedAttributes;
27
28 private final AttributeDictionary properties;
29 private final AttributeDictionary credentials;
30
31 LdifUser(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
32 this(userAdmin, dn, attributes, false);
33 }
34
35 private LdifUser(AbstractUserDirectory userAdmin, LdapName dn,
36 Attributes attributes, boolean frozen) {
37 this.userAdmin = userAdmin;
38 this.dn = dn;
39 this.publishedAttributes = attributes;
40 properties = new AttributeDictionary(false);
41 credentials = new AttributeDictionary(true);
42 this.frozen = frozen;
43 }
44
45 @Override
46 public String getName() {
47 return dn.toString();
48 }
49
50 @Override
51 public int getType() {
52 return USER;
53 }
54
55 @Override
56 public Dictionary<String, Object> getProperties() {
57 return properties;
58 }
59
60 @Override
61 public Dictionary<String, Object> getCredentials() {
62 return credentials;
63 }
64
65 @Override
66 public boolean hasCredential(String key, Object value) {
67 Object storedValue = getCredentials().get(key);
68 if (storedValue == null || value == null)
69 return false;
70 if (!(value instanceof String || value instanceof byte[]))
71 return false;
72 if (storedValue instanceof String && value instanceof String)
73 return storedValue.equals(value);
74 if (storedValue instanceof byte[] && value instanceof byte[])
75 return Arrays.equals((byte[]) storedValue, (byte[]) value);
76 return false;
77 }
78
79 @Override
80 public LdapName getDn() {
81 return dn;
82 }
83
84 @Override
85 public synchronized Attributes getAttributes() {
86 return isEditing() ? getModifiedAttributes() : publishedAttributes;
87 }
88
89 /** Should only be called from working copy thread. */
90 private synchronized Attributes getModifiedAttributes() {
91 assert getWc() != null;
92 return getWc().getAttributes(getDn());
93 }
94
95 protected synchronized boolean isEditing() {
96 return getWc() != null && getModifiedAttributes() != null;
97 }
98
99 private synchronized WorkingCopy getWc() {
100 return userAdmin.getWorkingCopy();
101 }
102
103 protected synchronized void startEditing() {
104 if (frozen)
105 throw new UserDirectoryException("Cannot edit frozen view");
106 if (getUserAdmin().isReadOnly())
107 throw new UserDirectoryException("User directory is read-only");
108 assert getModifiedAttributes() == null;
109 getWc().startEditing(this);
110 // modifiedAttributes = (Attributes) publishedAttributes.clone();
111 }
112
113 public synchronized void publishAttributes(Attributes modifiedAttributes) {
114 publishedAttributes = modifiedAttributes;
115 }
116
117 // protected synchronized void stopEditing(boolean apply) {
118 // assert getModifiedAttributes() != null;
119 // if (apply)
120 // publishedAttributes = getModifiedAttributes();
121 // // modifiedAttributes = null;
122 // }
123
124 public DirectoryUser getPublished() {
125 return new LdifUser(userAdmin, dn, publishedAttributes, true);
126 }
127
128 @Override
129 public int hashCode() {
130 return dn.hashCode();
131 }
132
133 @Override
134 public boolean equals(Object obj) {
135 if (this == obj)
136 return true;
137 if (obj instanceof LdifUser) {
138 LdifUser that = (LdifUser) obj;
139 return this.dn.equals(that.dn);
140 }
141 return false;
142 }
143
144 @Override
145 public String toString() {
146 return dn.toString();
147 }
148
149 protected AbstractUserDirectory getUserAdmin() {
150 return userAdmin;
151 }
152
153 private class AttributeDictionary extends Dictionary<String, Object> {
154 private final List<String> effectiveKeys = new ArrayList<String>();
155 private final List<String> attrFilter;
156 private final Boolean includeFilter;
157
158 public AttributeDictionary(Boolean includeFilter) {
159 this.attrFilter = userAdmin.getCredentialAttributeIds();
160 this.includeFilter = includeFilter;
161 try {
162 NamingEnumeration<String> ids = getAttributes().getIDs();
163 while (ids.hasMore()) {
164 String id = ids.next();
165 if (includeFilter && attrFilter.contains(id))
166 effectiveKeys.add(id);
167 else if (!includeFilter && !attrFilter.contains(id))
168 effectiveKeys.add(id);
169 }
170 } catch (NamingException e) {
171 throw new UserDirectoryException(
172 "Cannot initialise attribute dictionary", e);
173 }
174 }
175
176 @Override
177 public int size() {
178 return effectiveKeys.size();
179 }
180
181 @Override
182 public boolean isEmpty() {
183 return effectiveKeys.size() == 0;
184 }
185
186 @Override
187 public Enumeration<String> keys() {
188 return Collections.enumeration(effectiveKeys);
189 }
190
191 @Override
192 public Enumeration<Object> elements() {
193 final Iterator<String> it = effectiveKeys.iterator();
194 return new Enumeration<Object>() {
195
196 @Override
197 public boolean hasMoreElements() {
198 return it.hasNext();
199 }
200
201 @Override
202 public Object nextElement() {
203 String key = it.next();
204 try {
205 return getAttributes().get(key).get();
206 } catch (NamingException e) {
207 throw new UserDirectoryException(
208 "Cannot get value for key " + key, e);
209 }
210 }
211
212 };
213 }
214
215 @Override
216 public Object get(Object key) {
217 try {
218 Attribute attr = getAttributes().get(key.toString());
219 if (attr == null)
220 return null;
221 return attr.get();
222 } catch (NamingException e) {
223 throw new UserDirectoryException(
224 "Cannot get value for attribute " + key, e);
225 }
226 }
227
228 @Override
229 public Object put(String key, Object value) {
230 userAdmin.checkEdit();
231 if (!isEditing())
232 startEditing();
233
234 if (!(value instanceof String || value instanceof byte[]))
235 throw new IllegalArgumentException(
236 "Value must be String or byte[]");
237
238 if (includeFilter && !attrFilter.contains(key))
239 throw new IllegalArgumentException("Key " + key
240 + " not included");
241 else if (!includeFilter && attrFilter.contains(key))
242 throw new IllegalArgumentException("Key " + key + " excluded");
243
244 try {
245 Attribute attribute = getModifiedAttributes().get(
246 key.toString());
247 attribute = new BasicAttribute(key.toString());
248 attribute.add(value);
249 Attribute previousAttribute = getModifiedAttributes().put(
250 attribute);
251 if (previousAttribute != null)
252 return previousAttribute.get();
253 else
254 return null;
255 } catch (NamingException e) {
256 throw new UserDirectoryException(
257 "Cannot get value for attribute " + key, e);
258 }
259 }
260
261 @Override
262 public Object remove(Object key) {
263 userAdmin.checkEdit();
264 if (!isEditing())
265 startEditing();
266
267 if (includeFilter && !attrFilter.contains(key))
268 throw new IllegalArgumentException("Key " + key
269 + " not included");
270 else if (!includeFilter && attrFilter.contains(key))
271 throw new IllegalArgumentException("Key " + key + " excluded");
272
273 try {
274 Attribute attr = getModifiedAttributes().remove(key.toString());
275 if (attr != null)
276 return attr.get();
277 else
278 return null;
279 } catch (NamingException e) {
280 throw new UserDirectoryException("Cannot remove attribute "
281 + key, e);
282 }
283 }
284 }
285
286 }