]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java
Directory as a hierarchy unit.
[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.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 String usernameToUse;
97 String displayNameToUse;
98 if (user instanceof Group) {
99 // TODO check whether this is still working
100 String ownerDn = TokenUtils.userDn((Group) user);
101 if (ownerDn != null) {// tokens
102 UserAdmin ownerUserAdmin = findUserAdmin(ownerDn);
103 User ownerUser = (User) ownerUserAdmin.getRole(ownerDn);
104 usernameToUse = ownerDn;
105 displayNameToUse = LdifAuthorization.extractDisplayName(ownerUser);
106 } else {
107 usernameToUse = rawAuthorization.getName();
108 displayNameToUse = rawAuthorization.toString();
109 }
110 } else {// regular users
111 usernameToUse = rawAuthorization.getName();
112 displayNameToUse = rawAuthorization.toString();
113 }
114
115 // gather roles from other referentials
116 final DirectoryUserAdmin userAdminToUse;// possibly scoped when authenticating
117 if (user instanceof DirectoryUser) {
118 userAdminToUse = userReferentialOfThisUser;
119 } else if (user instanceof AuthenticatingUser) {
120 userAdminToUse = (DirectoryUserAdmin) userReferentialOfThisUser.scope(user);
121 } else {
122 throw new IllegalArgumentException("Unsupported user type " + user.getClass());
123 }
124
125 try {
126 Set<String> sysRoles = new HashSet<String>();
127 for (String role : rawAuthorization.getRoles()) {
128 User userOrGroup = (User) userAdminToUse.getRole(role);
129 Authorization auth = systemRoles.getAuthorization(userOrGroup);
130 systemRoles: for (String systemRole : auth.getRoles()) {
131 if (role.equals(systemRole))
132 continue systemRoles;
133 sysRoles.add(systemRole);
134 }
135 // sysRoles.addAll(Arrays.asList(auth.getRoles()));
136 }
137 addAbstractSystemRoles(rawAuthorization, sysRoles);
138 Authorization authorization = new AggregatingAuthorization(usernameToUse, displayNameToUse, sysRoles,
139 rawAuthorization.getRoles());
140 return authorization;
141 } finally {
142 if (userAdminToUse != null && userAdminToUse.isScoped()) {
143 userAdminToUse.destroy();
144 }
145 }
146 }
147
148 /**
149 * Enrich with application-specific roles which are strictly programmatic, such
150 * as anonymous/user semantics.
151 */
152 protected void addAbstractSystemRoles(Authorization rawAuthorization, Set<String> sysRoles) {
153
154 }
155
156 //
157 // USER ADMIN AGGREGATOR
158 //
159 protected void addUserDirectory(UserDirectory ud) {
160 if (!(ud instanceof DirectoryUserAdmin))
161 throw new IllegalArgumentException("Only " + DirectoryUserAdmin.class.getName() + " is supported");
162 DirectoryUserAdmin userDirectory = (DirectoryUserAdmin) ud;
163 String basePath = userDirectory.getContext();
164 if (isSystemRolesBaseDn(basePath)) {
165 this.systemRoles = userDirectory;
166 systemRoles.setExternalRoles(this);
167 } else if (isTokensBaseDn(basePath)) {
168 this.tokens = userDirectory;
169 tokens.setExternalRoles(this);
170 } else {
171 LdapName baseDn = toLdapName(basePath);
172 if (businessRoles.containsKey(baseDn))
173 throw new IllegalStateException("There is already a user admin for " + baseDn);
174 businessRoles.put(baseDn, userDirectory);
175 }
176 userDirectory.init();
177 postAdd(userDirectory);
178 }
179
180 /** Called after a new user directory has been added */
181 protected void postAdd(UserDirectory userDirectory) {
182 }
183
184 private DirectoryUserAdmin findUserAdmin(String name) {
185 try {
186 return findUserAdmin(new LdapName(name));
187 } catch (InvalidNameException e) {
188 throw new IllegalArgumentException("Badly formatted name " + name, e);
189 }
190 }
191
192 private DirectoryUserAdmin findUserAdmin(LdapName name) {
193 if (name.startsWith(systemRolesBaseDn))
194 return systemRoles;
195 if (tokensBaseDn != null && name.startsWith(tokensBaseDn))
196 return tokens;
197 List<DirectoryUserAdmin> res = new ArrayList<>(1);
198 userDirectories: for (LdapName baseDn : businessRoles.keySet()) {
199 DirectoryUserAdmin userDirectory = businessRoles.get(baseDn);
200 if (name.startsWith(baseDn)) {
201 if (userDirectory.isDisabled())
202 continue userDirectories;
203 // if (res.isEmpty()) {
204 res.add(userDirectory);
205 // } else {
206 // for (AbstractUserDirectory ud : res) {
207 // LdapName bd = ud.getBaseDn();
208 // if (userDirectory.getBaseDn().startsWith(bd)) {
209 // // child user directory
210 // }
211 // }
212 // }
213 }
214 }
215 if (res.size() == 0)
216 throw new IllegalStateException("Cannot find user admin for " + name);
217 if (res.size() > 1)
218 throw new IllegalStateException("Multiple user admin found for " + name);
219 return res.get(0);
220 }
221
222 protected boolean isSystemRolesBaseDn(String basePath) {
223 return toLdapName(basePath).equals(systemRolesBaseDn);
224 }
225
226 protected boolean isTokensBaseDn(String basePath) {
227 return tokensBaseDn != null && toLdapName(basePath).equals(tokensBaseDn);
228 }
229
230 // protected Dictionary<String, Object> currentState() {
231 // Dictionary<String, Object> res = new Hashtable<String, Object>();
232 // // res.put(NodeConstants.CN, NodeConstants.DEFAULT);
233 // for (LdapName name : businessRoles.keySet()) {
234 // AbstractUserDirectory userDirectory = businessRoles.get(name);
235 // String uri = UserAdminConf.propertiesAsUri(userDirectory.getProperties()).toString();
236 // res.put(uri, "");
237 // }
238 // return res;
239 // }
240
241 public void destroy() {
242 for (LdapName name : businessRoles.keySet()) {
243 DirectoryUserAdmin userDirectory = businessRoles.get(name);
244 destroy(userDirectory);
245 }
246 businessRoles.clear();
247 businessRoles = null;
248 destroy(systemRoles);
249 systemRoles = null;
250 }
251
252 private void destroy(DirectoryUserAdmin userDirectory) {
253 preDestroy(userDirectory);
254 userDirectory.destroy();
255 }
256
257 protected void removeUserDirectory(String basePath) {
258 if (isSystemRolesBaseDn(basePath))
259 throw new IllegalArgumentException("System roles cannot be removed ");
260 LdapName baseDn = toLdapName(basePath);
261 if (!businessRoles.containsKey(baseDn))
262 throw new IllegalStateException("No user directory registered for " + baseDn);
263 DirectoryUserAdmin userDirectory = businessRoles.remove(baseDn);
264 destroy(userDirectory);
265 }
266
267 /**
268 * Called before each user directory is destroyed, so that additional actions
269 * can be performed.
270 */
271 protected void preDestroy(UserDirectory userDirectory) {
272 }
273
274 public Set<UserDirectory> getUserDirectories() {
275 TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getContext().compareTo(o2.getContext()));
276 res.addAll(businessRoles.values());
277 return res;
278 }
279 }