]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java
Factorize indexed properties, thus fixing issue when creating a new user.
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / 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())
126 .equals(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 return findUserAdmin(name).removeRole(name);
179 }
180
181 @Override
182 public Role getRole(String name) {
183 return findUserAdmin(name).getRole(name);
184 }
185
186 @Override
187 public Role[] getRoles(String filter) throws InvalidSyntaxException {
188 List<Role> res = new ArrayList<Role>();
189 for (UserAdmin userAdmin : userAdmins.values()) {
190 res.addAll(Arrays.asList(userAdmin.getRoles(filter)));
191 }
192 res.addAll(Arrays.asList(nodeRoles.getRoles(filter)));
193 return res.toArray(new Role[res.size()]);
194 }
195
196 @Override
197 public User getUser(String key, String value) {
198 List<User> res = new ArrayList<User>();
199 for (UserAdmin userAdmin : userAdmins.values()) {
200 User u = userAdmin.getUser(key, value);
201 if (u != null)
202 res.add(u);
203 }
204 // Note: node roles cannot contain users, so it is not searched
205 return res.size() == 1 ? res.get(0) : null;
206 }
207
208 @Override
209 public Authorization getAuthorization(User user) {
210 if (user == null) {
211 return nodeRoles.getAuthorization(null);
212 }
213 UserAdmin userAdmin = findUserAdmin(user.getName());
214 Authorization rawAuthorization = userAdmin.getAuthorization(user);
215 // gather system roles
216 Set<String> systemRoles = new HashSet<String>();
217 for (String role : rawAuthorization.getRoles()) {
218 Authorization auth = nodeRoles.getAuthorization((User) userAdmin
219 .getRole(role));
220 systemRoles.addAll(Arrays.asList(auth.getRoles()));
221 }
222 return new NodeAuthorization(rawAuthorization.getName(),
223 rawAuthorization.toString(), systemRoles,
224 rawAuthorization.getRoles());
225 }
226
227 //
228 // USER ADMIN AGGREGATOR
229 //
230 public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) {
231 if (baseDn.equals(KernelHeader.ROLES_BASEDN)) {
232 nodeRoles = userAdmin;
233 return;
234 }
235
236 if (userAdmins.containsKey(baseDn))
237 throw new UserDirectoryException(
238 "There is already a user admin for " + baseDn);
239 try {
240 userAdmins.put(new LdapName(baseDn), userAdmin);
241 } catch (InvalidNameException e) {
242 throw new UserDirectoryException("Badly formatted base DN "
243 + baseDn, e);
244 }
245 }
246
247 public synchronized void removeUserAdmin(String baseDn) {
248 if (baseDn.equals(KernelHeader.ROLES_BASEDN))
249 throw new UserDirectoryException("Node roles cannot be removed.");
250 LdapName base;
251 try {
252 base = new LdapName(baseDn);
253 } catch (InvalidNameException e) {
254 throw new UserDirectoryException("Badly formatted base DN "
255 + baseDn, e);
256 }
257 if (!userAdmins.containsKey(base))
258 throw new UserDirectoryException("There is no user admin for "
259 + base);
260 userAdmins.remove(base);
261 }
262
263 private UserAdmin findUserAdmin(String name) {
264 try {
265 return findUserAdmin(new LdapName(name));
266 } catch (InvalidNameException e) {
267 throw new UserDirectoryException("Badly formatted name " + name, e);
268 }
269 }
270
271 private UserAdmin findUserAdmin(LdapName name) {
272 if (name.startsWith(ROLES_BASE))
273 return nodeRoles;
274 List<UserAdmin> res = new ArrayList<UserAdmin>(1);
275 for (LdapName baseDn : userAdmins.keySet()) {
276 if (name.startsWith(baseDn))
277 res.add(userAdmins.get(baseDn));
278 }
279 if (res.size() == 0)
280 throw new UserDirectoryException("Cannot find user admin for "
281 + name);
282 if (res.size() > 1)
283 throw new UserDirectoryException("Multiple user admin found for "
284 + name);
285 return res.get(0);
286 }
287
288 public void setTransactionManager(TransactionManager transactionManager) {
289 if (nodeRoles instanceof UserDirectory)
290 ((UserDirectory) nodeRoles)
291 .setTransactionManager(transactionManager);
292 for (UserAdmin userAdmin : userAdmins.values()) {
293 if (userAdmin instanceof UserDirectory)
294 ((UserDirectory) userAdmin)
295 .setTransactionManager(transactionManager);
296 }
297 }
298 }