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