]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java
Refactor WebDav implementation
[lgpl/argeo-commons.git] / org.argeo.util / src / org / argeo / osgi / useradmin / AggregatingUserAdmin.java
1 package org.argeo.osgi.useradmin;
2
3 import static org.argeo.osgi.useradmin.DirectoryUserAdmin.toLdapName;
4
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.Hashtable;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13 import java.util.TreeSet;
14
15 import javax.naming.InvalidNameException;
16 import javax.naming.ldap.LdapName;
17
18 import org.argeo.util.directory.DirectoryConf;
19 import org.osgi.framework.InvalidSyntaxException;
20 import org.osgi.service.useradmin.Authorization;
21 import org.osgi.service.useradmin.Group;
22 import org.osgi.service.useradmin.Role;
23 import org.osgi.service.useradmin.User;
24 import org.osgi.service.useradmin.UserAdmin;
25
26 /**
27 * Aggregates multiple {@link UserDirectory} and integrates them with system
28 * roles.
29 */
30 public class AggregatingUserAdmin implements UserAdmin {
31 private final LdapName systemRolesBaseDn;
32 private final LdapName tokensBaseDn;
33
34 // DAOs
35 private DirectoryUserAdmin systemRoles = null;
36 private DirectoryUserAdmin tokens = null;
37 private Map<LdapName, DirectoryUserAdmin> businessRoles = new HashMap<LdapName, DirectoryUserAdmin>();
38
39 // TODO rather use an empty constructor and an init method
40 public AggregatingUserAdmin(String systemRolesBaseDn, String tokensBaseDn) {
41 try {
42 this.systemRolesBaseDn = new LdapName(systemRolesBaseDn);
43 if (tokensBaseDn != null)
44 this.tokensBaseDn = new LdapName(tokensBaseDn);
45 else
46 this.tokensBaseDn = null;
47 } catch (InvalidNameException e) {
48 throw new IllegalStateException("Cannot initialize " + AggregatingUserAdmin.class, e);
49 }
50 }
51
52 @Override
53 public Role createRole(String name, int type) {
54 return findUserAdmin(name).createRole(name, type);
55 }
56
57 @Override
58 public boolean removeRole(String name) {
59 boolean actuallyDeleted = findUserAdmin(name).removeRole(name);
60 systemRoles.removeRole(name);
61 return actuallyDeleted;
62 }
63
64 @Override
65 public Role getRole(String name) {
66 return findUserAdmin(name).getRole(name);
67 }
68
69 @Override
70 public Role[] getRoles(String filter) throws InvalidSyntaxException {
71 List<Role> res = new ArrayList<Role>();
72 for (UserAdmin userAdmin : businessRoles.values()) {
73 res.addAll(Arrays.asList(userAdmin.getRoles(filter)));
74 }
75 res.addAll(Arrays.asList(systemRoles.getRoles(filter)));
76 return res.toArray(new Role[res.size()]);
77 }
78
79 @Override
80 public User getUser(String key, String value) {
81 List<User> res = new ArrayList<User>();
82 for (UserAdmin userAdmin : businessRoles.values()) {
83 User u = userAdmin.getUser(key, value);
84 if (u != null)
85 res.add(u);
86 }
87 // Note: node roles cannot contain users, so it is not searched
88 return res.size() == 1 ? res.get(0) : null;
89 }
90
91 @Override
92 public Authorization getAuthorization(User user) {
93 if (user == null) {// anonymous
94 return systemRoles.getAuthorization(null);
95 }
96 DirectoryUserAdmin userReferentialOfThisUser = findUserAdmin(user.getName());
97 Authorization rawAuthorization = userReferentialOfThisUser.getAuthorization(user);
98 User retrievedUser = (User) userReferentialOfThisUser.getRole(user.getName());
99 String usernameToUse;
100 String displayNameToUse;
101 if (user instanceof Group) {
102 // TODO check whether this is still working
103 String ownerDn = TokenUtils.userDn((Group) user);
104 if (ownerDn != null) {// tokens
105 UserAdmin ownerUserAdmin = findUserAdmin(ownerDn);
106 User ownerUser = (User) ownerUserAdmin.getRole(ownerDn);
107 usernameToUse = ownerDn;
108 displayNameToUse = LdifAuthorization.extractDisplayName(ownerUser);
109 } else {
110 usernameToUse = rawAuthorization.getName();
111 displayNameToUse = rawAuthorization.toString();
112 }
113 } else {// regular users
114 usernameToUse = rawAuthorization.getName();
115 displayNameToUse = rawAuthorization.toString();
116 }
117
118 // gather roles from other referentials
119 List<String> allRoles = new ArrayList<>(Arrays.asList(rawAuthorization.getRoles()));
120 for (LdapName otherBaseDn : businessRoles.keySet()) {
121 if (otherBaseDn.equals(userReferentialOfThisUser.getBaseDn()))
122 continue;
123 DirectoryUserAdmin otherUserAdmin = businessRoles.get(otherBaseDn);
124 Authorization auth = otherUserAdmin.getAuthorization(retrievedUser);
125 allRoles.addAll(Arrays.asList(auth.getRoles()));
126
127 }
128
129 // integrate system roles
130 final DirectoryUserAdmin userAdminToUse;// possibly scoped when authenticating
131 if (user instanceof DirectoryUser) {
132 userAdminToUse = userReferentialOfThisUser;
133 } else if (user instanceof AuthenticatingUser) {
134 userAdminToUse = (DirectoryUserAdmin) userReferentialOfThisUser.scope(user);
135 } else {
136 throw new IllegalArgumentException("Unsupported user type " + user.getClass());
137 }
138
139 try {
140 Set<String> sysRoles = new HashSet<String>();
141 for (String role : rawAuthorization.getRoles()) {
142 User userOrGroup = (User) userAdminToUse.getRole(role);
143 Authorization auth = systemRoles.getAuthorization(userOrGroup);
144 systemRoles: for (String systemRole : auth.getRoles()) {
145 if (role.equals(systemRole))
146 continue systemRoles;
147 sysRoles.add(systemRole);
148 }
149 // sysRoles.addAll(Arrays.asList(auth.getRoles()));
150 }
151 addAbstractSystemRoles(rawAuthorization, sysRoles);
152 Authorization authorization = new AggregatingAuthorization(usernameToUse, displayNameToUse, sysRoles,
153 allRoles.toArray(new String[allRoles.size()]));
154 return authorization;
155 } finally {
156 if (userAdminToUse != null && userAdminToUse.isScoped()) {
157 userAdminToUse.destroy();
158 }
159 }
160 }
161
162 /**
163 * Enrich with application-specific roles which are strictly programmatic, such
164 * as anonymous/user semantics.
165 */
166 protected void addAbstractSystemRoles(Authorization rawAuthorization, Set<String> sysRoles) {
167
168 }
169
170 //
171 // USER ADMIN AGGREGATOR
172 //
173 protected void addUserDirectory(UserDirectory ud) {
174 if (!(ud instanceof DirectoryUserAdmin))
175 throw new IllegalArgumentException("Only " + DirectoryUserAdmin.class.getName() + " is supported");
176 DirectoryUserAdmin userDirectory = (DirectoryUserAdmin) ud;
177 String basePath = userDirectory.getBase();
178 if (isSystemRolesBaseDn(basePath)) {
179 this.systemRoles = userDirectory;
180 systemRoles.setExternalRoles(this);
181 } else if (isTokensBaseDn(basePath)) {
182 this.tokens = userDirectory;
183 tokens.setExternalRoles(this);
184 } else {
185 LdapName baseDn = toLdapName(basePath);
186 if (businessRoles.containsKey(baseDn))
187 throw new IllegalStateException("There is already a user admin for " + baseDn);
188 businessRoles.put(baseDn, userDirectory);
189 }
190 userDirectory.init();
191 postAdd(userDirectory);
192 }
193
194 /** Called after a new user directory has been added */
195 protected void postAdd(UserDirectory userDirectory) {
196 }
197
198 private DirectoryUserAdmin findUserAdmin(String name) {
199 try {
200 return findUserAdmin(new LdapName(name));
201 } catch (InvalidNameException e) {
202 throw new IllegalArgumentException("Badly formatted name " + name, e);
203 }
204 }
205
206 private DirectoryUserAdmin findUserAdmin(LdapName name) {
207 if (name.startsWith(systemRolesBaseDn))
208 return systemRoles;
209 if (tokensBaseDn != null && name.startsWith(tokensBaseDn))
210 return tokens;
211 List<DirectoryUserAdmin> res = new ArrayList<>(1);
212 userDirectories: for (LdapName baseDn : businessRoles.keySet()) {
213 DirectoryUserAdmin userDirectory = businessRoles.get(baseDn);
214 if (name.startsWith(baseDn)) {
215 if (userDirectory.isDisabled())
216 continue userDirectories;
217 // if (res.isEmpty()) {
218 res.add(userDirectory);
219 // } else {
220 // for (AbstractUserDirectory ud : res) {
221 // LdapName bd = ud.getBaseDn();
222 // if (userDirectory.getBaseDn().startsWith(bd)) {
223 // // child user directory
224 // }
225 // }
226 // }
227 }
228 }
229 if (res.size() == 0)
230 throw new IllegalStateException("Cannot find user admin for " + name);
231 if (res.size() > 1)
232 throw new IllegalStateException("Multiple user admin found for " + name);
233 return res.get(0);
234 }
235
236 protected boolean isSystemRolesBaseDn(String basePath) {
237 return toLdapName(basePath).equals(systemRolesBaseDn);
238 }
239
240 protected boolean isTokensBaseDn(String basePath) {
241 return tokensBaseDn != null && toLdapName(basePath).equals(tokensBaseDn);
242 }
243
244 // protected Dictionary<String, Object> currentState() {
245 // Dictionary<String, Object> res = new Hashtable<String, Object>();
246 // // res.put(NodeConstants.CN, NodeConstants.DEFAULT);
247 // for (LdapName name : businessRoles.keySet()) {
248 // AbstractUserDirectory userDirectory = businessRoles.get(name);
249 // String uri = UserAdminConf.propertiesAsUri(userDirectory.getProperties()).toString();
250 // res.put(uri, "");
251 // }
252 // return res;
253 // }
254
255 public void start() {
256 if (systemRoles == null) {
257 // TODO do we really need separate system roles?
258 Hashtable<String, Object> properties = new Hashtable<>();
259 properties.put(DirectoryConf.baseDn.name(), "ou=roles,ou=system");
260 systemRoles = new DirectoryUserAdmin(properties);
261 }
262 }
263
264 public void stop() {
265 for (LdapName name : businessRoles.keySet()) {
266 DirectoryUserAdmin userDirectory = businessRoles.get(name);
267 destroy(userDirectory);
268 }
269 businessRoles.clear();
270 businessRoles = null;
271 destroy(systemRoles);
272 systemRoles = null;
273 }
274
275 private void destroy(DirectoryUserAdmin userDirectory) {
276 preDestroy(userDirectory);
277 userDirectory.destroy();
278 }
279
280 // protected void removeUserDirectory(UserDirectory userDirectory) {
281 // LdapName baseDn = toLdapName(userDirectory.getContext());
282 // businessRoles.remove(baseDn);
283 // if (userDirectory instanceof DirectoryUserAdmin)
284 // destroy((DirectoryUserAdmin) userDirectory);
285 // }
286
287 @Deprecated
288 protected void removeUserDirectory(String basePath) {
289 if (isSystemRolesBaseDn(basePath))
290 throw new IllegalArgumentException("System roles cannot be removed ");
291 LdapName baseDn = toLdapName(basePath);
292 if (!businessRoles.containsKey(baseDn))
293 throw new IllegalStateException("No user directory registered for " + baseDn);
294 DirectoryUserAdmin userDirectory = businessRoles.remove(baseDn);
295 destroy(userDirectory);
296 }
297
298 /**
299 * Called before each user directory is destroyed, so that additional actions
300 * can be performed.
301 */
302 protected void preDestroy(UserDirectory userDirectory) {
303 }
304
305 public Set<UserDirectory> getUserDirectories() {
306 TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getBase().compareTo(o2.getBase()));
307 res.addAll(businessRoles.values());
308 res.add(systemRoles);
309 return res;
310 }
311
312 }