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
;
9 import java
.util
.Hashtable
;
10 import java
.util
.List
;
13 import java
.util
.TreeSet
;
15 import javax
.naming
.InvalidNameException
;
16 import javax
.naming
.ldap
.LdapName
;
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
;
27 * Aggregates multiple {@link UserDirectory} and integrates them with system
30 public class AggregatingUserAdmin
implements UserAdmin
{
31 private final LdapName systemRolesBaseDn
;
32 private final LdapName tokensBaseDn
;
35 private DirectoryUserAdmin systemRoles
= null;
36 private DirectoryUserAdmin tokens
= null;
37 private Map
<LdapName
, DirectoryUserAdmin
> businessRoles
= new HashMap
<LdapName
, DirectoryUserAdmin
>();
39 // TODO rather use an empty constructor and an init method
40 public AggregatingUserAdmin(String systemRolesBaseDn
, String tokensBaseDn
) {
42 this.systemRolesBaseDn
= new LdapName(systemRolesBaseDn
);
43 if (tokensBaseDn
!= null)
44 this.tokensBaseDn
= new LdapName(tokensBaseDn
);
46 this.tokensBaseDn
= null;
47 } catch (InvalidNameException e
) {
48 throw new IllegalStateException("Cannot initialize " + AggregatingUserAdmin
.class, e
);
53 public Role
createRole(String name
, int type
) {
54 return findUserAdmin(name
).createRole(name
, type
);
58 public boolean removeRole(String name
) {
59 boolean actuallyDeleted
= findUserAdmin(name
).removeRole(name
);
60 systemRoles
.removeRole(name
);
61 return actuallyDeleted
;
65 public Role
getRole(String name
) {
66 return findUserAdmin(name
).getRole(name
);
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
)));
75 res
.addAll(Arrays
.asList(systemRoles
.getRoles(filter
)));
76 return res
.toArray(new Role
[res
.size()]);
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
);
87 // Note: node roles cannot contain users, so it is not searched
88 return res
.size() == 1 ? res
.get(0) : null;
92 public Authorization
getAuthorization(User user
) {
93 if (user
== null) {// anonymous
94 return systemRoles
.getAuthorization(null);
96 DirectoryUserAdmin userReferentialOfThisUser
= findUserAdmin(user
.getName());
97 Authorization rawAuthorization
= userReferentialOfThisUser
.getAuthorization(user
);
98 User retrievedUser
= (User
) userReferentialOfThisUser
.getRole(user
.getName());
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
);
110 usernameToUse
= rawAuthorization
.getName();
111 displayNameToUse
= rawAuthorization
.toString();
113 } else {// regular users
114 usernameToUse
= rawAuthorization
.getName();
115 displayNameToUse
= rawAuthorization
.toString();
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()))
123 DirectoryUserAdmin otherUserAdmin
= businessRoles
.get(otherBaseDn
);
124 Authorization auth
= otherUserAdmin
.getAuthorization(retrievedUser
);
125 allRoles
.addAll(Arrays
.asList(auth
.getRoles()));
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
);
136 throw new IllegalArgumentException("Unsupported user type " + user
.getClass());
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
);
149 // sysRoles.addAll(Arrays.asList(auth.getRoles()));
151 addAbstractSystemRoles(rawAuthorization
, sysRoles
);
152 Authorization authorization
= new AggregatingAuthorization(usernameToUse
, displayNameToUse
, sysRoles
,
153 allRoles
.toArray(new String
[allRoles
.size()]));
154 return authorization
;
156 if (userAdminToUse
!= null && userAdminToUse
.isScoped()) {
157 userAdminToUse
.destroy();
163 * Enrich with application-specific roles which are strictly programmatic, such
164 * as anonymous/user semantics.
166 protected void addAbstractSystemRoles(Authorization rawAuthorization
, Set
<String
> sysRoles
) {
171 // USER ADMIN AGGREGATOR
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);
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
);
190 userDirectory
.init();
191 postAdd(userDirectory
);
194 /** Called after a new user directory has been added */
195 protected void postAdd(UserDirectory userDirectory
) {
198 private DirectoryUserAdmin
findUserAdmin(String name
) {
200 return findUserAdmin(new LdapName(name
));
201 } catch (InvalidNameException e
) {
202 throw new IllegalArgumentException("Badly formatted name " + name
, e
);
206 private DirectoryUserAdmin
findUserAdmin(LdapName name
) {
207 if (name
.startsWith(systemRolesBaseDn
))
209 if (tokensBaseDn
!= null && name
.startsWith(tokensBaseDn
))
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
);
220 // for (AbstractUserDirectory ud : res) {
221 // LdapName bd = ud.getBaseDn();
222 // if (userDirectory.getBaseDn().startsWith(bd)) {
223 // // child user directory
230 throw new IllegalStateException("Cannot find user admin for " + name
);
232 throw new IllegalStateException("Multiple user admin found for " + name
);
236 protected boolean isSystemRolesBaseDn(String basePath
) {
237 return toLdapName(basePath
).equals(systemRolesBaseDn
);
240 protected boolean isTokensBaseDn(String basePath
) {
241 return tokensBaseDn
!= null && toLdapName(basePath
).equals(tokensBaseDn
);
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();
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
);
265 for (LdapName name
: businessRoles
.keySet()) {
266 DirectoryUserAdmin userDirectory
= businessRoles
.get(name
);
267 destroy(userDirectory
);
269 businessRoles
.clear();
270 businessRoles
= null;
271 destroy(systemRoles
);
275 private void destroy(DirectoryUserAdmin userDirectory
) {
276 preDestroy(userDirectory
);
277 userDirectory
.destroy();
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);
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
);
299 * Called before each user directory is destroyed, so that additional actions
302 protected void preDestroy(UserDirectory userDirectory
) {
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
);