View Javadoc
1   package org.argeo.osgi.useradmin;
2   
3   import java.util.ArrayList;
4   import java.util.Arrays;
5   import java.util.HashMap;
6   import java.util.HashSet;
7   import java.util.List;
8   import java.util.Map;
9   import java.util.Set;
10  
11  import javax.naming.InvalidNameException;
12  import javax.naming.ldap.LdapName;
13  
14  import org.osgi.framework.InvalidSyntaxException;
15  import org.osgi.service.useradmin.Authorization;
16  import org.osgi.service.useradmin.Group;
17  import org.osgi.service.useradmin.Role;
18  import org.osgi.service.useradmin.User;
19  import org.osgi.service.useradmin.UserAdmin;
20  
21  /**
22   * Aggregates multiple {@link UserDirectory} and integrates them with system
23   * roles.
24   */
25  public class AggregatingUserAdmin implements UserAdmin {
26  	private final LdapName systemRolesBaseDn;
27  	private final LdapName tokensBaseDn;
28  
29  	// DAOs
30  	private AbstractUserDirectory systemRoles = null;
31  	private AbstractUserDirectory tokens = null;
32  	private Map<LdapName, AbstractUserDirectory> businessRoles = new HashMap<LdapName, AbstractUserDirectory>();
33  
34  	public AggregatingUserAdmin(String systemRolesBaseDn, String tokensBaseDn) {
35  		try {
36  			this.systemRolesBaseDn = new LdapName(systemRolesBaseDn);
37  			if (tokensBaseDn != null)
38  				this.tokensBaseDn = new LdapName(tokensBaseDn);
39  			else
40  				this.tokensBaseDn = null;
41  		} catch (InvalidNameException e) {
42  			throw new UserDirectoryException("Cannot initialize " + AggregatingUserAdmin.class, e);
43  		}
44  	}
45  
46  	@Override
47  	public Role createRole(String name, int type) {
48  		return findUserAdmin(name).createRole(name, type);
49  	}
50  
51  	@Override
52  	public boolean removeRole(String name) {
53  		boolean actuallyDeleted = findUserAdmin(name).removeRole(name);
54  		systemRoles.removeRole(name);
55  		return actuallyDeleted;
56  	}
57  
58  	@Override
59  	public Role getRole(String name) {
60  		return findUserAdmin(name).getRole(name);
61  	}
62  
63  	@Override
64  	public Role[] getRoles(String filter) throws InvalidSyntaxException {
65  		List<Role> res = new ArrayList<Role>();
66  		for (UserAdmin userAdmin : businessRoles.values()) {
67  			res.addAll(Arrays.asList(userAdmin.getRoles(filter)));
68  		}
69  		res.addAll(Arrays.asList(systemRoles.getRoles(filter)));
70  		return res.toArray(new Role[res.size()]);
71  	}
72  
73  	@Override
74  	public User getUser(String key, String value) {
75  		List<User> res = new ArrayList<User>();
76  		for (UserAdmin userAdmin : businessRoles.values()) {
77  			User u = userAdmin.getUser(key, value);
78  			if (u != null)
79  				res.add(u);
80  		}
81  		// Note: node roles cannot contain users, so it is not searched
82  		return res.size() == 1 ? res.get(0) : null;
83  	}
84  
85  	@Override
86  	public Authorization getAuthorization(User user) {
87  		if (user == null) {// anonymous
88  			return systemRoles.getAuthorization(null);
89  		}
90  		UserAdmin userAdmin = findUserAdmin(user.getName());
91  		Authorization rawAuthorization = userAdmin.getAuthorization(user);
92  		String usernameToUse;
93  		String displayNameToUse;
94  		if (user instanceof Group) {
95  			String ownerDn = TokenUtils.userDn((Group) user);
96  			if (ownerDn != null) {// tokens
97  				UserAdmin ownerUserAdmin = findUserAdmin(ownerDn);
98  				User ownerUser = (User) ownerUserAdmin.getRole(ownerDn);
99  				usernameToUse = ownerDn;
100 				displayNameToUse = LdifAuthorization.extractDisplayName(ownerUser);
101 			} else {
102 				usernameToUse = rawAuthorization.getName();
103 				displayNameToUse = rawAuthorization.toString();
104 			}
105 		} else {// regular users
106 			usernameToUse = rawAuthorization.getName();
107 			displayNameToUse = rawAuthorization.toString();
108 		}
109 		// gather system roles
110 		Set<String> sysRoles = new HashSet<String>();
111 		for (String role : rawAuthorization.getRoles()) {
112 			Authorization auth = systemRoles.getAuthorization((User) userAdmin.getRole(role));
113 			sysRoles.addAll(Arrays.asList(auth.getRoles()));
114 		}
115 		addAbstractSystemRoles(rawAuthorization, sysRoles);
116 		Authorization authorization = new AggregatingAuthorization(usernameToUse, displayNameToUse, sysRoles,
117 				rawAuthorization.getRoles());
118 		return authorization;
119 	}
120 
121 	/**
122 	 * Enrich with application-specific roles which are strictly programmatic, such
123 	 * as anonymous/user semantics.
124 	 */
125 	protected void addAbstractSystemRoles(Authorization rawAuthorization, Set<String> sysRoles) {
126 
127 	}
128 
129 	//
130 	// USER ADMIN AGGREGATOR
131 	//
132 	protected void addUserDirectory(AbstractUserDirectory userDirectory) {
133 		LdapName baseDn = userDirectory.getBaseDn();
134 		if (isSystemRolesBaseDn(baseDn)) {
135 			this.systemRoles = userDirectory;
136 			systemRoles.setExternalRoles(this);
137 		} else if (isTokensBaseDn(baseDn)) {
138 			this.tokens = userDirectory;
139 			tokens.setExternalRoles(this);
140 		} else {
141 			if (businessRoles.containsKey(baseDn))
142 				throw new UserDirectoryException("There is already a user admin for " + baseDn);
143 			businessRoles.put(baseDn, userDirectory);
144 		}
145 		userDirectory.init();
146 		postAdd(userDirectory);
147 	}
148 
149 	/** Called after a new user directory has been added */
150 	protected void postAdd(AbstractUserDirectory userDirectory) {
151 	}
152 
153 	private UserAdmin findUserAdmin(String name) {
154 		try {
155 			UserAdmin userAdmin = findUserAdmin(new LdapName(name));
156 			return userAdmin;
157 		} catch (InvalidNameException e) {
158 			throw new UserDirectoryException("Badly formatted name " + name, e);
159 		}
160 	}
161 
162 	private UserAdmin findUserAdmin(LdapName name) {
163 		if (name.startsWith(systemRolesBaseDn))
164 			return systemRoles;
165 		if (tokensBaseDn != null && name.startsWith(tokensBaseDn))
166 			return tokens;
167 		List<UserAdmin> res = new ArrayList<UserAdmin>(1);
168 		for (LdapName baseDn : businessRoles.keySet()) {
169 			AbstractUserDirectory ud = businessRoles.get(baseDn);
170 			if (name.startsWith(baseDn)) {
171 				if (!ud.isDisabled())
172 					res.add(ud);
173 			}
174 //			Object principal = ud.getProperties().get(Context.SECURITY_PRINCIPAL);
175 //			if (principal != null) {
176 //				try {
177 //					LdapName principalLdapName = new LdapName(principal.toString());
178 //					if (principalLdapName.equals(name))
179 //						res.add(ud);
180 //				} catch (InvalidNameException e) {
181 //					// silent
182 //				}
183 //			}
184 		}
185 		if (res.size() == 0)
186 			throw new UserDirectoryException("Cannot find user admin for " + name);
187 		if (res.size() > 1)
188 			throw new UserDirectoryException("Multiple user admin found for " + name);
189 		return res.get(0);
190 	}
191 
192 	protected boolean isSystemRolesBaseDn(LdapName baseDn) {
193 		return baseDn.equals(systemRolesBaseDn);
194 	}
195 
196 	protected boolean isTokensBaseDn(LdapName baseDn) {
197 		return tokensBaseDn != null && baseDn.equals(tokensBaseDn);
198 	}
199 
200 //	protected Dictionary<String, Object> currentState() {
201 //		Dictionary<String, Object> res = new Hashtable<String, Object>();
202 //		// res.put(NodeConstants.CN, NodeConstants.DEFAULT);
203 //		for (LdapName name : businessRoles.keySet()) {
204 //			AbstractUserDirectory userDirectory = businessRoles.get(name);
205 //			String uri = UserAdminConf.propertiesAsUri(userDirectory.getProperties()).toString();
206 //			res.put(uri, "");
207 //		}
208 //		return res;
209 //	}
210 
211 	public void destroy() {
212 		for (LdapName name : businessRoles.keySet()) {
213 			AbstractUserDirectory userDirectory = businessRoles.get(name);
214 			destroy(userDirectory);
215 		}
216 		businessRoles.clear();
217 		businessRoles = null;
218 		destroy(systemRoles);
219 		systemRoles = null;
220 	}
221 
222 	private void destroy(AbstractUserDirectory userDirectory) {
223 		preDestroy(userDirectory);
224 		userDirectory.destroy();
225 	}
226 
227 	protected void removeUserDirectory(LdapName baseDn) {
228 		if (isSystemRolesBaseDn(baseDn))
229 			throw new UserDirectoryException("System roles cannot be removed ");
230 		if (!businessRoles.containsKey(baseDn))
231 			throw new UserDirectoryException("No user directory registered for " + baseDn);
232 		AbstractUserDirectory userDirectory = businessRoles.remove(baseDn);
233 		destroy(userDirectory);
234 	}
235 
236 	/**
237 	 * Called before each user directory is destroyed, so that additional actions
238 	 * can be performed.
239 	 */
240 	protected void preDestroy(AbstractUserDirectory userDirectory) {
241 	}
242 
243 }