1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.security;
35
36 import static info.magnolia.cms.security.SecurityConstants.NODE_ROLES;
37 import info.magnolia.cms.core.ItemType;
38 import info.magnolia.cms.core.Path;
39 import info.magnolia.cms.security.auth.ACL;
40 import info.magnolia.cms.util.SimpleUrlPattern;
41 import info.magnolia.cms.util.UrlPattern;
42 import info.magnolia.context.MgnlContext;
43 import info.magnolia.jcr.util.NodeTypes;
44 import info.magnolia.repository.RepositoryConstants;
45
46 import java.util.ArrayList;
47 import java.util.Collection;
48 import java.util.Collections;
49 import java.util.HashMap;
50 import java.util.LinkedList;
51 import java.util.List;
52 import java.util.Map;
53
54 import javax.jcr.ItemNotFoundException;
55 import javax.jcr.Node;
56 import javax.jcr.NodeIterator;
57 import javax.jcr.PathNotFoundException;
58 import javax.jcr.Property;
59 import javax.jcr.PropertyIterator;
60 import javax.jcr.RepositoryException;
61 import javax.jcr.Session;
62 import javax.jcr.ValueFormatException;
63
64 import org.apache.commons.lang.StringUtils;
65 import org.apache.jackrabbit.commons.iterator.FilteringNodeIterator;
66 import org.apache.jackrabbit.commons.predicate.NodeTypePredicate;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70
71
72
73
74
75 public abstract class RepositoryBackedSecurityManager {
76
77 private static final Logger log = LoggerFactory.getLogger(RepositoryBackedSecurityManager.class);
78
79 public boolean hasAny(final String principalName, final String resourceName, final String resourceTypeName) {
80 long start = System.currentTimeMillis();
81 try {
82 String sessionName;
83 if (StringUtils.equalsIgnoreCase(resourceTypeName, NODE_ROLES)) {
84 sessionName = RepositoryConstants.USER_ROLES;
85 } else {
86 sessionName = RepositoryConstants.USER_GROUPS;
87 }
88
89
90
91 final Collection<String> groupsOrRoles = MgnlContext.doInSystemContext(new JCRSessionOp<Collection<String>>(getRepositoryName()) {
92
93 @Override
94 public Collection<String> exec(Session session) throws RepositoryException {
95 List<String> list = new ArrayList<String>();
96 Node principal = findPrincipalNode(principalName, session);
97 if(principal == null) {
98 log.debug("No User '"+principalName+"' found in repository");
99 return list;
100 }
101 Node groupsOrRoles = principal.getNode(resourceTypeName);
102
103 for (PropertyIterator props = groupsOrRoles.getProperties(); props.hasNext();) {
104 Property property = props.nextProperty();
105 try {
106
107 list.add(property.getString());
108 } catch (ItemNotFoundException e) {
109 log.debug("Role [{}] does not exist in the {} repository", resourceName, resourceTypeName);
110 } catch (IllegalArgumentException e) {
111 log.debug("{} has invalid value", property.getPath());
112 } catch (ValueFormatException e) {
113 log.debug("{} has invalid value", property.getPath());
114 }
115 }
116 return list;
117 }
118 });
119
120
121
122 return MgnlContext.doInSystemContext(new JCRSessionOp<Boolean>(sessionName) {
123
124 @Override
125 public Boolean exec(Session session) throws RepositoryException {
126 for (String groupOrRole : groupsOrRoles) {
127
128 try {
129 if (session.getNodeByIdentifier(groupOrRole).getName().equalsIgnoreCase(resourceName)) {
130 return true;
131 }
132 } catch (RepositoryException e) {
133 log.debug("Role [{}] does not exist in the ROLES repository", resourceName);
134 }
135 }
136 return false;
137 }});
138
139 } catch (RepositoryException e) {
140
141 log.debug(e.getMessage(), e);
142 } finally {
143 log.debug("checked {} for {} in {}ms.", new Object[] {resourceName, resourceTypeName, (System.currentTimeMillis() - start)});
144 }
145 return false;
146 }
147
148
149
150
151
152
153
154
155
156 protected void add(final String principalName, final String resourceName, final String resourceTypeName) throws PrincipalNotFoundException {
157 try {
158 final String nodeID = getLinkedResourceId(resourceName, resourceTypeName);
159
160 if (!hasAny(principalName, resourceName, resourceTypeName)) {
161 Session session = MgnlContext.getJCRSession(getRepositoryName());
162 Node principalNode = findPrincipalNode(principalName, session);
163 if (principalNode == null) {
164 throw new PrincipalNotFoundException("Principal " + principalName + " of type " + resourceTypeName + " was not found.");
165 }
166 if (!principalNode.hasNode(resourceTypeName)) {
167 principalNode.addNode(resourceTypeName, ItemType.CONTENTNODE.getSystemName());
168 }
169 Node node = principalNode.getNode(resourceTypeName);
170
171
172 String newName = Path.getUniqueLabel(session, node.getPath(), "0");
173 node.setProperty(newName, nodeID);
174 session.save();
175 }
176 }
177 catch (RepositoryException e) {
178 log.error("failed to add " + resourceTypeName + " "+ resourceName + " to [" + principalName + "]", e);
179 }
180 }
181
182 private String getLinkedResourceId(final String resourceName, final String resourceTypeName) throws AccessDeniedException {
183 final String nodeID;
184 if (StringUtils.equalsIgnoreCase(resourceTypeName, NODE_ROLES)) {
185 Role role = SecuritySupport.Factory.getInstance().getRoleManager().getRole(resourceName);
186 if (role == null) {
187 log.warn("Invalid role requested: {}", resourceName);
188 nodeID = null;
189 }
190 else {
191 nodeID = role.getId();
192 }
193 }
194 else {
195 Group group = SecuritySupport.Factory.getInstance().getGroupManager().getGroup(resourceName);
196 if (group == null) {
197 log.warn("Invalid group requested: {}", resourceName);
198 nodeID = null;
199 }
200 else {
201 nodeID = group.getId();
202 }
203 }
204 return nodeID;
205 }
206
207 protected String getResourceName(final String resourceId) {
208 try {
209 return MgnlContext.getJCRSession(getRepositoryName()).getNodeByIdentifier(resourceId).getName();
210 } catch (ItemNotFoundException e) {
211
212 return null;
213 }
214 catch (RepositoryException e) {
215 log.error(e.getMessage(), e);
216 }
217 return null;
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231 protected void remove(final String principalName, final String resourceName, final String resourceTypeName) throws PrincipalNotFoundException {
232 try {
233 final String nodeID = getLinkedResourceId(resourceName, resourceTypeName);
234
235 if (hasAny(principalName, resourceName, resourceTypeName)) {
236 Session session = MgnlContext.getJCRSession(getRepositoryName());
237 Node principalNode = findPrincipalNode(principalName, session);
238 if (!principalNode.hasNode(resourceTypeName)) {
239 throw new PrincipalNotFoundException("Principal " + principalName + " of type " + resourceTypeName + " was not found.");
240 }
241 Node node = principalNode.getNode(resourceTypeName);
242 for (PropertyIterator iter = node.getProperties(); iter.hasNext();) {
243 Property nodeData = iter.nextProperty();
244
245 try {
246 if (nodeData.getString().equals(nodeID)) {
247 nodeData.remove();
248 session.save();
249
250 }
251 } catch (IllegalArgumentException e) {
252 log.debug("{} has invalid value", nodeData.getPath());
253 } catch (ValueFormatException e) {
254 log.debug("{} has invalid value", nodeData.getPath());
255 }
256 }
257 }
258 }
259 catch (RepositoryException e) {
260 log.error("failed to remove " + resourceTypeName + " "+ resourceName + " from [" + principalName + "]", e);
261 }
262 }
263
264 protected abstract String getRepositoryName();
265
266 protected abstract Node findPrincipalNode(String principalName, Session session) throws RepositoryException;
267
268 protected Node findPrincipalNode(String principalName, Session session, String primaryNodeType) throws RepositoryException {
269 return findPrincipalNode(principalName, session, primaryNodeType, null);
270 }
271
272
273
274
275
276
277
278
279
280
281 protected Node findPrincipalNode(String principalName, Session session, String primaryNodeType, Node startNode) throws RepositoryException {
282 LinkedList<Node> nodes = new LinkedList<Node>();
283
284 final Node rootNode = startNode == null ? session.getRootNode() : startNode;
285
286 for (NodeIterator iterator = rootNode.getNodes(); iterator.hasNext(); ) {
287 final Node node = iterator.nextNode();
288 if (!node.getName().startsWith(NodeTypes.JCR_PREFIX) && !node.getName().startsWith(NodeTypes.REP_PREFIX)) {
289 nodes.add(node);
290 }
291 }
292
293 Node principalNode = null;
294 while (!nodes.isEmpty()) {
295 final Node node = nodes.removeFirst();
296
297 if (node.getName().equals(principalName) && node.getPrimaryNodeType().getName().equals(primaryNodeType)) {
298 if (principalNode != null) {
299 log.error("More than one principal node found of type \"{}\" with name \"{}\"", primaryNodeType, principalName);
300 break;
301 }
302 principalNode = node;
303 }
304
305 int i = 0;
306 for (NodeIterator iterator = node.getNodes(); iterator.hasNext(); ) {
307 nodes.add(i++, iterator.nextNode());
308 }
309 }
310 return principalNode;
311 }
312
313 public Map<String, ACL> getACLs(final String principalName) {
314 return MgnlContext.doInSystemContext(new SilentSessionOp<Map<String,ACL>>(getRepositoryName()) {
315 @Override
316 public Map<String, ACL> doExec(Session session) throws Throwable {
317 Node node = findPrincipalNode(principalName, session);
318 if(node == null){
319 return Collections.emptyMap();
320 }
321 return getACLs(node);
322 }});
323 }
324
325 protected Map<String, ACL> getACLs(Node node) throws RepositoryException, ValueFormatException, PathNotFoundException {
326 Map<String, ACL> principalList = new HashMap<String, ACL>();
327 NodeIterator it = new FilteringNodeIterator(node.getNodes(), new NodeTypePredicate(ItemType.CONTENTNODE.getSystemName(), true));
328 while (it.hasNext()) {
329 Node aclEntry = it.nextNode();
330 if (!aclEntry.getName().startsWith("acl")) {
331 continue;
332 }
333 String name = StringUtils.substringAfter(aclEntry.getName(), "acl_");
334
335 List<Permission> permissionList = new ArrayList<Permission>();
336
337 NodeIterator permissionIterator = new FilteringNodeIterator(aclEntry.getNodes(), new NodeTypePredicate(ItemType.CONTENTNODE.getSystemName(), true));
338 while (permissionIterator.hasNext()) {
339 Node map = permissionIterator.nextNode();
340 String path = map.getProperty("path").getString();
341 UrlPattern p = new SimpleUrlPattern(path);
342 Permission permission = new PermissionImpl();
343 permission.setPattern(p);
344 permission.setPermissions(map.getProperty("permissions").getLong());
345 permissionList.add(permission);
346 }
347
348 ACL acl;
349
350
351 if (principalList.containsKey(name)) {
352 acl = principalList.get(name);
353 permissionList.addAll(acl.getList());
354 }
355 acl = new ACLImpl(name, permissionList);
356 principalList.put(name, acl);
357
358 }
359 return principalList;
360 }
361
362 }