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