]> git.argeo.org Git - lgpl/argeo-commons.git/blob - NodeUserAdmin.java
31295ae89fac8f58b04fe3ba0ed78247a229c086
[lgpl/argeo-commons.git] / NodeUserAdmin.java
1 package org.argeo.cms.internal.kernel;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.URI;
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Dictionary;
9 import java.util.HashMap;
10 import java.util.HashSet;
11 import java.util.Hashtable;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15
16 import javax.naming.InvalidNameException;
17 import javax.naming.ldap.LdapName;
18 import javax.transaction.TransactionManager;
19
20 import org.apache.commons.io.FileUtils;
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.argeo.cms.CmsException;
24 import org.argeo.cms.KernelHeader;
25 import org.argeo.osgi.useradmin.LdapUserAdmin;
26 import org.argeo.osgi.useradmin.LdifUserAdmin;
27 import org.argeo.osgi.useradmin.UserAdminConf;
28 import org.argeo.osgi.useradmin.UserDirectory;
29 import org.argeo.osgi.useradmin.UserDirectoryException;
30 import org.osgi.framework.InvalidSyntaxException;
31 import org.osgi.service.useradmin.Authorization;
32 import org.osgi.service.useradmin.Role;
33 import org.osgi.service.useradmin.User;
34 import org.osgi.service.useradmin.UserAdmin;
35
36 public class NodeUserAdmin implements UserAdmin {
37 private final static Log log = LogFactory.getLog(NodeUserAdmin.class);
38 final static LdapName ROLES_BASE;
39 static {
40 try {
41 ROLES_BASE = new LdapName(KernelHeader.ROLES_BASEDN);
42 } catch (InvalidNameException e) {
43 throw new UserDirectoryException("Cannot initialize "
44 + NodeUserAdmin.class, e);
45 }
46 }
47
48 private UserAdmin nodeRoles = null;
49 private Map<LdapName, UserAdmin> userAdmins = new HashMap<LdapName, UserAdmin>();
50
51 public NodeUserAdmin() {
52 File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
53 File nodeBaseDir = new File(osgiInstanceDir, "node");
54 nodeBaseDir.mkdirs();
55
56 String userAdminUri = KernelUtils
57 .getFrameworkProp(KernelConstants.USERADMIN_URIS);
58 if (userAdminUri == null) {
59 String demoBaseDn = "dc=example,dc=com";
60 File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif");
61 if (!businessRolesFile.exists())
62 try {
63 FileUtils.copyInputStreamToFile(getClass()
64 .getResourceAsStream(demoBaseDn + ".ldif"),
65 businessRolesFile);
66 } catch (IOException e) {
67 throw new CmsException("Cannot copy demo resource", e);
68 }
69 userAdminUri = businessRolesFile.toURI().toString();
70 }
71
72 String[] uris = userAdminUri.split(" ");
73 for (String uri : uris) {
74 URI u;
75 try {
76 u = new URI(uri);
77 if (u.getPath() == null)
78 throw new CmsException("URI " + uri
79 + " must have a path in order to determine base DN");
80 if (u.getScheme() == null) {
81 if (uri.startsWith("/") || uri.startsWith("./")
82 || uri.startsWith("../"))
83 u = new File(uri).getCanonicalFile().toURI();
84 else if (!uri.contains("/"))
85 u = new File(nodeBaseDir, uri).getCanonicalFile()
86 .toURI();
87 else
88 throw new CmsException("Cannot interpret " + uri
89 + " as an uri");
90 } else if (u.getScheme().equals("file")) {
91 u = new File(u).getCanonicalFile().toURI();
92 }
93 } catch (Exception e) {
94 throw new CmsException(
95 "Cannot interpret " + uri + " as an uri", e);
96 }
97 Dictionary<String, ?> properties = UserAdminConf.uriAsProperties(u
98 .toString());
99 UserDirectory businessRoles;
100 if (u.getScheme().startsWith("ldap")) {
101 businessRoles = new LdapUserAdmin(properties);
102 } else {
103 businessRoles = new LdifUserAdmin(properties);
104 }
105 businessRoles.init();
106 addUserAdmin(businessRoles.getBaseDn(), (UserAdmin) businessRoles);
107 if (log.isDebugEnabled())
108 log.debug("User directory " + businessRoles.getBaseDn() + " ["
109 + u.getScheme() + "] enabled.");
110 }
111
112 // NOde roles
113 String nodeRolesUri = KernelUtils
114 .getFrameworkProp(KernelConstants.ROLES_URI);
115 String baseNodeRoleDn = KernelHeader.ROLES_BASEDN;
116 if (nodeRolesUri == null) {
117 File nodeRolesFile = new File(nodeBaseDir, baseNodeRoleDn + ".ldif");
118 if (!nodeRolesFile.exists())
119 try {
120 FileUtils.copyInputStreamToFile(getClass()
121 .getResourceAsStream("demo.ldif"), nodeRolesFile);
122 } catch (IOException e) {
123 throw new CmsException("Cannot copy demo resource", e);
124 }
125 nodeRolesUri = nodeRolesFile.toURI().toString();
126 }
127
128 Dictionary<String, ?> nodeRolesProperties = UserAdminConf
129 .uriAsProperties(nodeRolesUri);
130 if (!nodeRolesProperties.get(UserAdminConf.baseDn.property()).equals(
131 baseNodeRoleDn)) {
132 throw new CmsException("Invalid base dn for node roles");
133 // TODO deal with "mounted" roles with a different baseDN
134 }
135 UserDirectory nodeRoles;
136 if (nodeRolesUri.startsWith("ldap")) {
137 nodeRoles = new LdapUserAdmin(nodeRolesProperties);
138 } else {
139 nodeRoles = new LdifUserAdmin(nodeRolesProperties);
140 }
141 nodeRoles.setExternalRoles(this);
142 nodeRoles.init();
143 addUserAdmin(baseNodeRoleDn, (UserAdmin) nodeRoles);
144 if (log.isTraceEnabled())
145 log.trace("Node roles enabled.");
146 }
147
148 Dictionary<String, ?> currentState() {
149 Dictionary<String, Object> res = new Hashtable<String, Object>();
150 for (LdapName name : userAdmins.keySet()) {
151 StringBuilder buf = new StringBuilder();
152 if (userAdmins.get(name) instanceof UserDirectory) {
153 UserDirectory userDirectory = (UserDirectory) userAdmins
154 .get(name);
155 String uri = UserAdminConf.propertiesAsUri(
156 userDirectory.getProperties()).toString();
157 res.put(uri, "");
158 } else {
159 buf.append('/').append(name.toString())
160 .append("?readOnly=true");
161 }
162 }
163 return res;
164 }
165
166 public void destroy() {
167 for (LdapName name : userAdmins.keySet()) {
168 if (userAdmins.get(name) instanceof UserDirectory) {
169 UserDirectory userDirectory = (UserDirectory) userAdmins
170 .get(name);
171 userDirectory.destroy();
172 }
173 }
174 }
175
176 @Override
177 public Role createRole(String name, int type) {
178 return findUserAdmin(name).createRole(name, type);
179 }
180
181 @Override
182 public boolean removeRole(String name) {
183 boolean actuallyDeleted = findUserAdmin(name).removeRole(name);
184 nodeRoles.removeRole(name);
185 return actuallyDeleted;
186 }
187
188 @Override
189 public Role getRole(String name) {
190 return findUserAdmin(name).getRole(name);
191 }
192
193 @Override
194 public Role[] getRoles(String filter) throws InvalidSyntaxException {
195 List<Role> res = new ArrayList<Role>();
196 for (UserAdmin userAdmin : userAdmins.values()) {
197 res.addAll(Arrays.asList(userAdmin.getRoles(filter)));
198 }
199 res.addAll(Arrays.asList(nodeRoles.getRoles(filter)));
200 return res.toArray(new Role[res.size()]);
201 }
202
203 @Override
204 public User getUser(String key, String value) {
205 List<User> res = new ArrayList<User>();
206 for (UserAdmin userAdmin : userAdmins.values()) {
207 User u = userAdmin.getUser(key, value);
208 if (u != null)
209 res.add(u);
210 }
211 // Note: node roles cannot contain users, so it is not searched
212 return res.size() == 1 ? res.get(0) : null;
213 }
214
215 @Override
216 public Authorization getAuthorization(User user) {
217 if (user == null) {
218 return nodeRoles.getAuthorization(null);
219 }
220 UserAdmin userAdmin = findUserAdmin(user.getName());
221 Authorization rawAuthorization = userAdmin.getAuthorization(user);
222 // gather system roles
223 Set<String> systemRoles = new HashSet<String>();
224 for (String role : rawAuthorization.getRoles()) {
225 Authorization auth = nodeRoles.getAuthorization((User) userAdmin
226 .getRole(role));
227 systemRoles.addAll(Arrays.asList(auth.getRoles()));
228 }
229 return new NodeAuthorization(rawAuthorization.getName(),
230 rawAuthorization.toString(), systemRoles,
231 rawAuthorization.getRoles());
232 }
233
234 //
235 // USER ADMIN AGGREGATOR
236 //
237 public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) {
238 if (baseDn.equals(KernelHeader.ROLES_BASEDN)) {
239 nodeRoles = userAdmin;
240 return;
241 }
242
243 if (userAdmins.containsKey(baseDn))
244 throw new UserDirectoryException(
245 "There is already a user admin for " + baseDn);
246 try {
247 userAdmins.put(new LdapName(baseDn), userAdmin);
248 } catch (InvalidNameException e) {
249 throw new UserDirectoryException("Badly formatted base DN "
250 + baseDn, e);
251 }
252 }
253
254 public synchronized void removeUserAdmin(String baseDn) {
255 if (baseDn.equals(KernelHeader.ROLES_BASEDN))
256 throw new UserDirectoryException("Node roles cannot be removed.");
257 LdapName base;
258 try {
259 base = new LdapName(baseDn);
260 } catch (InvalidNameException e) {
261 throw new UserDirectoryException("Badly formatted base DN "
262 + baseDn, e);
263 }
264 if (!userAdmins.containsKey(base))
265 throw new UserDirectoryException("There is no user admin for "
266 + base);
267 userAdmins.remove(base);
268 }
269
270 private UserAdmin findUserAdmin(String name) {
271 try {
272 return findUserAdmin(new LdapName(name));
273 } catch (InvalidNameException e) {
274 throw new UserDirectoryException("Badly formatted name " + name, e);
275 }
276 }
277
278 private UserAdmin findUserAdmin(LdapName name) {
279 if (name.startsWith(ROLES_BASE))
280 return nodeRoles;
281 List<UserAdmin> res = new ArrayList<UserAdmin>(1);
282 for (LdapName baseDn : userAdmins.keySet()) {
283 if (name.startsWith(baseDn))
284 res.add(userAdmins.get(baseDn));
285 }
286 if (res.size() == 0)
287 throw new UserDirectoryException("Cannot find user admin for "
288 + name);
289 if (res.size() > 1)
290 throw new UserDirectoryException("Multiple user admin found for "
291 + name);
292 return res.get(0);
293 }
294
295 public void setTransactionManager(TransactionManager transactionManager) {
296 if (nodeRoles instanceof UserDirectory)
297 ((UserDirectory) nodeRoles)
298 .setTransactionManager(transactionManager);
299 for (UserAdmin userAdmin : userAdmins.values()) {
300 if (userAdmin instanceof UserDirectory)
301 ((UserDirectory) userAdmin)
302 .setTransactionManager(transactionManager);
303 }
304 }
305 }