1 package org
.argeo
.osgi
.useradmin
;
3 import static org
.argeo
.osgi
.useradmin
.DirectoryUserAdmin
.toLdapName
;
5 import java
.util
.ArrayList
;
6 import java
.util
.Arrays
;
7 import java
.util
.HashMap
;
8 import java
.util
.HashSet
;
12 import java
.util
.TreeSet
;
14 import javax
.naming
.InvalidNameException
;
15 import javax
.naming
.ldap
.LdapName
;
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
;
25 * Aggregates multiple {@link UserDirectory} and integrates them with system
28 public class AggregatingUserAdmin
implements UserAdmin
{
29 private final LdapName systemRolesBaseDn
;
30 private final LdapName tokensBaseDn
;
33 private DirectoryUserAdmin systemRoles
= null;
34 private DirectoryUserAdmin tokens
= null;
35 private Map
<LdapName
, DirectoryUserAdmin
> businessRoles
= new HashMap
<LdapName
, DirectoryUserAdmin
>();
37 // TODO rather use an empty constructor and an init method
38 public AggregatingUserAdmin(String systemRolesBaseDn
, String tokensBaseDn
) {
40 this.systemRolesBaseDn
= new LdapName(systemRolesBaseDn
);
41 if (tokensBaseDn
!= null)
42 this.tokensBaseDn
= new LdapName(tokensBaseDn
);
44 this.tokensBaseDn
= null;
45 } catch (InvalidNameException e
) {
46 throw new IllegalStateException("Cannot initialize " + AggregatingUserAdmin
.class, e
);
51 public Role
createRole(String name
, int type
) {
52 return findUserAdmin(name
).createRole(name
, type
);
56 public boolean removeRole(String name
) {
57 boolean actuallyDeleted
= findUserAdmin(name
).removeRole(name
);
58 systemRoles
.removeRole(name
);
59 return actuallyDeleted
;
63 public Role
getRole(String name
) {
64 return findUserAdmin(name
).getRole(name
);
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
)));
73 res
.addAll(Arrays
.asList(systemRoles
.getRoles(filter
)));
74 return res
.toArray(new Role
[res
.size()]);
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
);
85 // Note: node roles cannot contain users, so it is not searched
86 return res
.size() == 1 ? res
.get(0) : null;
90 public Authorization
getAuthorization(User user
) {
91 if (user
== null) {// anonymous
92 return systemRoles
.getAuthorization(null);
94 DirectoryUserAdmin userReferentialOfThisUser
= findUserAdmin(user
.getName());
95 Authorization rawAuthorization
= userReferentialOfThisUser
.getAuthorization(user
);
96 User retrievedUser
= (User
) userReferentialOfThisUser
.getRole(user
.getName());
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
);
108 usernameToUse
= rawAuthorization
.getName();
109 displayNameToUse
= rawAuthorization
.toString();
111 } else {// regular users
112 usernameToUse
= rawAuthorization
.getName();
113 displayNameToUse
= rawAuthorization
.toString();
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()))
121 DirectoryUserAdmin otherUserAdmin
= businessRoles
.get(otherBaseDn
);
122 Authorization auth
= otherUserAdmin
.getAuthorization(retrievedUser
);
123 allRoles
.addAll(Arrays
.asList(auth
.getRoles()));
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
);
134 throw new IllegalArgumentException("Unsupported user type " + user
.getClass());
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
);
147 // sysRoles.addAll(Arrays.asList(auth.getRoles()));
149 addAbstractSystemRoles(rawAuthorization
, sysRoles
);
150 Authorization authorization
= new AggregatingAuthorization(usernameToUse
, displayNameToUse
, sysRoles
,
151 allRoles
.toArray(new String
[allRoles
.size()]));
152 return authorization
;
154 if (userAdminToUse
!= null && userAdminToUse
.isScoped()) {
155 userAdminToUse
.destroy();
161 * Enrich with application-specific roles which are strictly programmatic, such
162 * as anonymous/user semantics.
164 protected void addAbstractSystemRoles(Authorization rawAuthorization
, Set
<String
> sysRoles
) {
169 // USER ADMIN AGGREGATOR
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);
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
);
188 userDirectory
.init();
189 postAdd(userDirectory
);
192 /** Called after a new user directory has been added */
193 protected void postAdd(UserDirectory userDirectory
) {
196 private DirectoryUserAdmin
findUserAdmin(String name
) {
198 return findUserAdmin(new LdapName(name
));
199 } catch (InvalidNameException e
) {
200 throw new IllegalArgumentException("Badly formatted name " + name
, e
);
204 private DirectoryUserAdmin
findUserAdmin(LdapName name
) {
205 if (name
.startsWith(systemRolesBaseDn
))
207 if (tokensBaseDn
!= null && name
.startsWith(tokensBaseDn
))
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
);
218 // for (AbstractUserDirectory ud : res) {
219 // LdapName bd = ud.getBaseDn();
220 // if (userDirectory.getBaseDn().startsWith(bd)) {
221 // // child user directory
228 throw new IllegalStateException("Cannot find user admin for " + name
);
230 throw new IllegalStateException("Multiple user admin found for " + name
);
234 protected boolean isSystemRolesBaseDn(String basePath
) {
235 return toLdapName(basePath
).equals(systemRolesBaseDn
);
238 protected boolean isTokensBaseDn(String basePath
) {
239 return tokensBaseDn
!= null && toLdapName(basePath
).equals(tokensBaseDn
);
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();
253 public void start() {
258 for (LdapName name
: businessRoles
.keySet()) {
259 DirectoryUserAdmin userDirectory
= businessRoles
.get(name
);
260 destroy(userDirectory
);
262 businessRoles
.clear();
263 businessRoles
= null;
264 destroy(systemRoles
);
268 private void destroy(DirectoryUserAdmin userDirectory
) {
269 preDestroy(userDirectory
);
270 userDirectory
.destroy();
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);
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
);
292 * Called before each user directory is destroyed, so that additional actions
295 protected void preDestroy(UserDirectory userDirectory
) {
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
);