]> git.argeo.org Git - lgpl/argeo-commons.git/blob - NodeUserAdmin.java
e396ca09e6b7d5e0e0b0c314b0715505d09789d3
[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.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.UserAdminAggregator;
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, UserAdminAggregator {
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 private TransactionManager transactionManager;
53
54 public NodeUserAdmin() {
55 File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
56 File nodeBaseDir = new File(osgiInstanceDir, "node");
57 nodeBaseDir.mkdirs();
58
59 String userAdminUri = KernelUtils
60 .getFrameworkProp(KernelConstants.USERADMIN_URI);
61 if (userAdminUri == null) {
62 String demoBaseDn = "dc=example,dc=com";
63 File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif");
64 if (!businessRolesFile.exists())
65 try {
66 FileUtils.copyInputStreamToFile(getClass()
67 .getResourceAsStream(demoBaseDn + ".ldif"),
68 businessRolesFile);
69 } catch (IOException e) {
70 throw new CmsException("Cannot copy demo resource", e);
71 }
72 userAdminUri = businessRolesFile.toURI().toString();
73 }
74
75 String[] uris = userAdminUri.split(" ");
76 for (String uri : uris) {
77 URI u;
78 try {
79 u = new URI(uri);
80 if (u.getScheme() == null) {
81 if (uri.startsWith("/"))
82 u = new File(uri).getAbsoluteFile().toURI();
83 else if (!uri.contains("/"))
84 u = new File(nodeBaseDir, uri).getAbsoluteFile()
85 .toURI();
86 else
87 throw new CmsException("Cannot interpret " + uri
88 + " as an uri");
89 }
90 } catch (URISyntaxException e) {
91 throw new CmsException(
92 "Cannot interpret " + uri + " as an uri", e);
93 }
94 Dictionary<String, ?> properties = LdapProperties.uriAsProperties(u
95 .toString());
96 AbstractUserDirectory businessRoles;
97 if (u.getScheme().startsWith("ldap")) {
98 businessRoles = new LdapUserAdmin(properties);
99 } else {
100 businessRoles = new LdifUserAdmin(properties);
101 }
102 businessRoles.init();
103 addUserAdmin(businessRoles.getBaseDn(), businessRoles);
104 if (log.isDebugEnabled())
105 log.debug("User directory " + businessRoles.getBaseDn() + " ["
106 + u.getScheme() + "] enabled.");
107 }
108
109 // NOde roles
110 String nodeRolesUri = KernelUtils
111 .getFrameworkProp(KernelConstants.ROLES_URI);
112 String baseNodeRoleDn = KernelHeader.ROLES_BASEDN;
113 if (nodeRolesUri == null) {
114 File nodeRolesFile = new File(nodeBaseDir, baseNodeRoleDn + ".ldif");
115 if (!nodeRolesFile.exists())
116 try {
117 FileUtils.copyInputStreamToFile(getClass()
118 .getResourceAsStream("demo.ldif"), nodeRolesFile);
119 } catch (IOException e) {
120 throw new CmsException("Cannot copy demo resource", e);
121 }
122 nodeRolesUri = nodeRolesFile.toURI().toString();
123 }
124
125 Dictionary<String, ?> nodeRolesProperties = LdapProperties
126 .uriAsProperties(nodeRolesUri);
127 if (!nodeRolesProperties.get(LdapProperties.baseDn.getFullName())
128 .equals(baseNodeRoleDn)) {
129 throw new CmsException("Invalid base dn for node roles");
130 // TODO deal with "mounted" roles with a different baseDN
131 }
132 AbstractUserDirectory nodeRoles;
133 if (nodeRolesUri.startsWith("ldap")) {
134 nodeRoles = new LdapUserAdmin(nodeRolesProperties);
135 } else {
136 nodeRoles = new LdifUserAdmin(nodeRolesProperties);
137 }
138 nodeRoles.setExternalRoles(this);
139 nodeRoles.init();
140 addUserAdmin(baseNodeRoleDn, nodeRoles);
141 if (log.isTraceEnabled())
142 log.trace("Node roles enabled.");
143 }
144
145 String asConfigUris() {
146 StringBuilder buf = new StringBuilder();
147 for (LdapName name : userAdmins.keySet()) {
148 buf.append('/').append(name.toString());
149 if (userAdmins.get(name) instanceof AbstractUserDirectory) {
150 AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
151 .get(name);
152 if (userDirectory.isReadOnly())
153 buf.append('?').append(LdapProperties.readOnly.name())
154 .append("=true");
155 }
156 buf.append(' ');
157 }
158 return buf.toString();
159 }
160
161 public void destroy() {
162 for (LdapName name : userAdmins.keySet()) {
163 if (userAdmins.get(name) instanceof AbstractUserDirectory) {
164 AbstractUserDirectory userDirectory = (AbstractUserDirectory) 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 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 @Override
228 public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) {
229 if (baseDn.equals(KernelHeader.ROLES_BASEDN)) {
230 nodeRoles = userAdmin;
231 return;
232 }
233
234 if (userAdmins.containsKey(baseDn))
235 throw new UserDirectoryException(
236 "There is already a user admin for " + baseDn);
237 try {
238 userAdmins.put(new LdapName(baseDn), userAdmin);
239 } catch (InvalidNameException e) {
240 throw new UserDirectoryException("Badly formatted base DN "
241 + baseDn, e);
242 }
243 }
244
245 @Override
246 public synchronized void removeUserAdmin(String baseDn) {
247 if (baseDn.equals(KernelHeader.ROLES_BASEDN))
248 throw new UserDirectoryException("Node roles cannot be removed.");
249 LdapName base;
250 try {
251 base = new LdapName(baseDn);
252 } catch (InvalidNameException e) {
253 throw new UserDirectoryException("Badly formatted base DN "
254 + baseDn, e);
255 }
256 if (!userAdmins.containsKey(base))
257 throw new UserDirectoryException("There is no user admin for "
258 + base);
259 userAdmins.remove(base);
260 }
261
262 private UserAdmin findUserAdmin(String name) {
263 try {
264 return findUserAdmin(new LdapName(name));
265 } catch (InvalidNameException e) {
266 throw new UserDirectoryException("Badly formatted name " + name, e);
267 }
268 }
269
270 private UserAdmin findUserAdmin(LdapName name) {
271 if (name.startsWith(ROLES_BASE))
272 return nodeRoles;
273 List<UserAdmin> res = new ArrayList<UserAdmin>(1);
274 for (LdapName baseDn : userAdmins.keySet()) {
275 if (name.startsWith(baseDn))
276 res.add(userAdmins.get(baseDn));
277 }
278 if (res.size() == 0)
279 throw new UserDirectoryException("Cannot find user admin for "
280 + name);
281 if (res.size() > 1)
282 throw new UserDirectoryException("Multiple user admin found for "
283 + name);
284 return res.get(0);
285 }
286
287 public void setTransactionManager(TransactionManager transactionManager) {
288 this.transactionManager = transactionManager;
289 if (nodeRoles instanceof AbstractUserDirectory)
290 ((AbstractUserDirectory) nodeRoles)
291 .setTransactionManager(transactionManager);
292 for (UserAdmin userAdmin : userAdmins.values()) {
293 if (userAdmin instanceof AbstractUserDirectory)
294 ((AbstractUserDirectory) userAdmin)
295 .setTransactionManager(transactionManager);
296 }
297 }
298 }