]> git.argeo.org Git - lgpl/argeo-commons.git/blob - kernel/NodeUserAdmin.java
Prepare next development cycle
[lgpl/argeo-commons.git] / 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.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.AbstractUserDirectory;
26 import org.argeo.osgi.useradmin.LdapProperties;
27 import org.argeo.osgi.useradmin.LdapUserAdmin;
28 import org.argeo.osgi.useradmin.LdifUserAdmin;
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_URI);
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.getScheme() == null) {
78 if (uri.startsWith("/"))
79 u = new File(uri).getAbsoluteFile().toURI();
80 else if (!uri.contains("/"))
81 u = new File(nodeBaseDir, uri).getAbsoluteFile()
82 .toURI();
83 else
84 throw new CmsException("Cannot interpret " + uri
85 + " as an uri");
86 }
87 } catch (URISyntaxException e) {
88 throw new CmsException(
89 "Cannot interpret " + uri + " as an uri", e);
90 }
91 Dictionary<String, ?> properties = LdapProperties.uriAsProperties(u
92 .toString());
93 AbstractUserDirectory businessRoles;
94 if (u.getScheme().startsWith("ldap")) {
95 businessRoles = new LdapUserAdmin(properties);
96 } else {
97 businessRoles = new LdifUserAdmin(properties);
98 }
99 businessRoles.init();
100 addUserAdmin(businessRoles.getBaseDn(), businessRoles);
101 if (log.isDebugEnabled())
102 log.debug("User directory " + businessRoles.getBaseDn() + " ["
103 + u.getScheme() + "] enabled.");
104 }
105
106 // NOde roles
107 String nodeRolesUri = KernelUtils
108 .getFrameworkProp(KernelConstants.ROLES_URI);
109 String baseNodeRoleDn = KernelHeader.ROLES_BASEDN;
110 if (nodeRolesUri == null) {
111 File nodeRolesFile = new File(nodeBaseDir, baseNodeRoleDn + ".ldif");
112 if (!nodeRolesFile.exists())
113 try {
114 FileUtils.copyInputStreamToFile(getClass()
115 .getResourceAsStream("demo.ldif"), nodeRolesFile);
116 } catch (IOException e) {
117 throw new CmsException("Cannot copy demo resource", e);
118 }
119 nodeRolesUri = nodeRolesFile.toURI().toString();
120 }
121
122 Dictionary<String, ?> nodeRolesProperties = LdapProperties
123 .uriAsProperties(nodeRolesUri);
124 if (!nodeRolesProperties.get(LdapProperties.baseDn.getFullName())
125 .equals(baseNodeRoleDn)) {
126 throw new CmsException("Invalid base dn for node roles");
127 // TODO deal with "mounted" roles with a different baseDN
128 }
129 AbstractUserDirectory nodeRoles;
130 if (nodeRolesUri.startsWith("ldap")) {
131 nodeRoles = new LdapUserAdmin(nodeRolesProperties);
132 } else {
133 nodeRoles = new LdifUserAdmin(nodeRolesProperties);
134 }
135 nodeRoles.setExternalRoles(this);
136 nodeRoles.init();
137 addUserAdmin(baseNodeRoleDn, nodeRoles);
138 if (log.isTraceEnabled())
139 log.trace("Node roles enabled.");
140 }
141
142 String asConfigUris() {
143 StringBuilder buf = new StringBuilder();
144 for (LdapName name : userAdmins.keySet()) {
145 buf.append('/').append(name.toString());
146 if (userAdmins.get(name) instanceof AbstractUserDirectory) {
147 AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
148 .get(name);
149 if (userDirectory.isReadOnly())
150 buf.append('?').append(LdapProperties.readOnly.name())
151 .append("=true");
152 }
153 buf.append(' ');
154 }
155 return buf.toString();
156 }
157
158 public void destroy() {
159 for (LdapName name : userAdmins.keySet()) {
160 if (userAdmins.get(name) instanceof AbstractUserDirectory) {
161 AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
162 .get(name);
163 userDirectory.destroy();
164 }
165 }
166 }
167
168 @Override
169 public Role createRole(String name, int type) {
170 return findUserAdmin(name).createRole(name, type);
171 }
172
173 @Override
174 public boolean removeRole(String name) {
175 return findUserAdmin(name).removeRole(name);
176 }
177
178 @Override
179 public Role getRole(String name) {
180 return findUserAdmin(name).getRole(name);
181 }
182
183 @Override
184 public Role[] getRoles(String filter) throws InvalidSyntaxException {
185 List<Role> res = new ArrayList<Role>();
186 for (UserAdmin userAdmin : userAdmins.values()) {
187 res.addAll(Arrays.asList(userAdmin.getRoles(filter)));
188 }
189 res.addAll(Arrays.asList(nodeRoles.getRoles(filter)));
190 return res.toArray(new Role[res.size()]);
191 }
192
193 @Override
194 public User getUser(String key, String value) {
195 List<User> res = new ArrayList<User>();
196 for (UserAdmin userAdmin : userAdmins.values()) {
197 User u = userAdmin.getUser(key, value);
198 if (u != null)
199 res.add(u);
200 }
201 // Note: node roles cannot contain users, so it is not searched
202 return res.size() == 1 ? res.get(0) : null;
203 }
204
205 @Override
206 public Authorization getAuthorization(User user) {
207 if (user == null) {
208 return nodeRoles.getAuthorization(null);
209 }
210 UserAdmin userAdmin = findUserAdmin(user.getName());
211 Authorization rawAuthorization = userAdmin.getAuthorization(user);
212 // gather system roles
213 Set<String> systemRoles = new HashSet<String>();
214 for (String role : rawAuthorization.getRoles()) {
215 Authorization auth = nodeRoles.getAuthorization((User) userAdmin
216 .getRole(role));
217 systemRoles.addAll(Arrays.asList(auth.getRoles()));
218 }
219 return new NodeAuthorization(rawAuthorization.getName(),
220 rawAuthorization.toString(), systemRoles,
221 rawAuthorization.getRoles());
222 }
223
224 //
225 // USER ADMIN AGGREGATOR
226 //
227 public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) {
228 if (baseDn.equals(KernelHeader.ROLES_BASEDN)) {
229 nodeRoles = userAdmin;
230 return;
231 }
232
233 if (userAdmins.containsKey(baseDn))
234 throw new UserDirectoryException(
235 "There is already a user admin for " + baseDn);
236 try {
237 userAdmins.put(new LdapName(baseDn), userAdmin);
238 } catch (InvalidNameException e) {
239 throw new UserDirectoryException("Badly formatted base DN "
240 + baseDn, e);
241 }
242 }
243
244 public synchronized void removeUserAdmin(String baseDn) {
245 if (baseDn.equals(KernelHeader.ROLES_BASEDN))
246 throw new UserDirectoryException("Node roles cannot be removed.");
247 LdapName base;
248 try {
249 base = new LdapName(baseDn);
250 } catch (InvalidNameException e) {
251 throw new UserDirectoryException("Badly formatted base DN "
252 + baseDn, e);
253 }
254 if (!userAdmins.containsKey(base))
255 throw new UserDirectoryException("There is no user admin for "
256 + base);
257 userAdmins.remove(base);
258 }
259
260 private UserAdmin findUserAdmin(String name) {
261 try {
262 return findUserAdmin(new LdapName(name));
263 } catch (InvalidNameException e) {
264 throw new UserDirectoryException("Badly formatted name " + name, e);
265 }
266 }
267
268 private UserAdmin findUserAdmin(LdapName name) {
269 if (name.startsWith(ROLES_BASE))
270 return nodeRoles;
271 List<UserAdmin> res = new ArrayList<UserAdmin>(1);
272 for (LdapName baseDn : userAdmins.keySet()) {
273 if (name.startsWith(baseDn))
274 res.add(userAdmins.get(baseDn));
275 }
276 if (res.size() == 0)
277 throw new UserDirectoryException("Cannot find user admin for "
278 + name);
279 if (res.size() > 1)
280 throw new UserDirectoryException("Multiple user admin found for "
281 + name);
282 return res.get(0);
283 }
284
285 public void setTransactionManager(TransactionManager transactionManager) {
286 if (nodeRoles instanceof AbstractUserDirectory)
287 ((AbstractUserDirectory) nodeRoles)
288 .setTransactionManager(transactionManager);
289 for (UserAdmin userAdmin : userAdmins.values()) {
290 if (userAdmin instanceof AbstractUserDirectory)
291 ((AbstractUserDirectory) userAdmin)
292 .setTransactionManager(transactionManager);
293 }
294 }
295 }