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.context.MgnlContext.VoidOp;
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.List;
51 import java.util.Map;
52
53 import javax.jcr.ItemNotFoundException;
54 import javax.jcr.Node;
55 import javax.jcr.NodeIterator;
56 import javax.jcr.PathNotFoundException;
57 import javax.jcr.Property;
58 import javax.jcr.PropertyIterator;
59 import javax.jcr.RepositoryException;
60 import javax.jcr.Session;
61 import javax.jcr.ValueFormatException;
62
63 import org.apache.commons.lang.StringUtils;
64 import org.apache.jackrabbit.commons.iterator.FilteringNodeIterator;
65 import org.apache.jackrabbit.commons.predicate.NodeTypePredicate;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69
70
71
72
73
74 public abstract class RepositoryBackedSecurityManager {
75
76 private static final Logger log = LoggerFactory.getLogger(RepositoryBackedSecurityManager.class);
77
78 public boolean hasAny(final String principalName, final String resourceName, final String resourceTypeName) {
79 long start = System.currentTimeMillis();
80 try {
81 String sessionName;
82 if (StringUtils.equalsIgnoreCase(resourceTypeName, NODE_ROLES)) {
83 sessionName = RepositoryConstants.USER_ROLES;
84 } else {
85 sessionName = RepositoryConstants.USER_GROUPS;
86 }
87
88
89
90 final Collection<String> groupsOrRoles = MgnlContext.doInSystemContext(new JCRSessionOp<Collection<String>>(getRepositoryName()) {
91
92 @Override
93 public Collection<String> exec(Session session) throws RepositoryException {
94 List<String> list = new ArrayList<String>();
95 Node principal = findPrincipalNode(principalName, session);
96 if(principal == null) {
97 log.debug("No User '"+principalName+"' found in repository");
98 return list;
99 }
100 Node groupsOrRoles = principal.getNode(resourceTypeName);
101
102 for (PropertyIterator props = groupsOrRoles.getProperties(); props.hasNext();) {
103 Property property = props.nextProperty();
104 try {
105
106 list.add(property.getString());
107 } catch (ItemNotFoundException e) {
108 log.debug("Role [{}] does not exist in the {} repository", resourceName, resourceTypeName);
109 } catch (IllegalArgumentException e) {
110 log.debug("{} has invalid value", property.getPath());
111 }
112 }
113 return list;
114 }
115 });
116
117
118
119 return MgnlContext.doInSystemContext(new JCRSessionOp<Boolean>(sessionName) {
120
121 @Override
122 public Boolean exec(Session session) throws RepositoryException {
123 for (String groupOrRole : groupsOrRoles) {
124
125 try {
126 if (session.getNodeByIdentifier(groupOrRole).getName().equalsIgnoreCase(resourceName)) {
127 return true;
128 }
129 } catch (ItemNotFoundException e) {
130 log.debug("Role [{}] does not exist in the ROLES repository", resourceName);
131 }
132 }
133 return false;
134 }});
135
136 } catch (RepositoryException e) {
137
138 log.debug(e.getMessage(), e);
139 } finally {
140 log.debug("checked {} for {} in {}ms.", new Object[] {resourceName, resourceTypeName, (System.currentTimeMillis() - start)});
141 }
142 return false;
143 }
144
145
146
147
148
149
150
151
152
153 protected void add(final String principalName, final String resourceName, final String resourceTypeName) throws PrincipalNotFoundException {
154 try {
155 final String nodeID = getLinkedResourceId(resourceName, resourceTypeName);
156
157 if (!hasAny(principalName, resourceName, resourceTypeName)) {
158 Session session = MgnlContext.getJCRSession(getRepositoryName());
159 Node principalNode = findPrincipalNode(principalName, session);
160 if (principalNode == null) {
161 throw new PrincipalNotFoundException("Principal " + principalName + " of type " + resourceTypeName + " was not found.");
162 }
163 if (!principalNode.hasNode(resourceTypeName)) {
164 principalNode.addNode(resourceTypeName, ItemType.CONTENTNODE.getSystemName());
165 }
166 Node node = principalNode.getNode(resourceTypeName);
167
168
169 String newName = Path.getUniqueLabel(session, node.getPath(), "0");
170 node.setProperty(newName, nodeID);
171 session.save();
172 }
173 }
174 catch (RepositoryException e) {
175 log.error("failed to add " + resourceTypeName + " "+ resourceName + " to [" + principalName + "]", e);
176 }
177 }
178
179 private String getLinkedResourceId(final String resourceName, final String resourceTypeName) throws AccessDeniedException {
180 final String nodeID;
181 if (StringUtils.equalsIgnoreCase(resourceTypeName, NODE_ROLES)) {
182 Role role = SecuritySupport.Factory.getInstance().getRoleManager().getRole(resourceName);
183 if (role == null) {
184 log.warn("Invalid role requested: {}", resourceName);
185 nodeID = null;
186 }
187 else {
188 nodeID = role.getId();
189 }
190 }
191 else {
192 nodeID = SecuritySupport.Factory.getInstance().getGroupManager().getGroup(resourceName).getId();
193 }
194 return nodeID;
195 }
196
197 protected String getResourceName(final String resourceId) {
198 try {
199 return MgnlContext.getJCRSession(getRepositoryName()).getNodeByIdentifier(resourceId).getName();
200 } catch (ItemNotFoundException e) {
201
202 return null;
203 }
204 catch (RepositoryException e) {
205 log.error(e.getMessage(), e);
206 }
207 return null;
208 }
209
210 protected void remove(final String principalName, final String resourceName, final String resourceTypeName) {
211
212 try {
213 final String nodeID = getLinkedResourceId(resourceName, resourceTypeName);
214
215 if (hasAny(principalName, resourceName, resourceTypeName)) {
216 MgnlContext.doInSystemContext(new SilentSessionOp<VoidOp>(getRepositoryName()) {
217
218 @Override
219 public VoidOp doExec(Session session) throws RepositoryException {
220 Node principalNode = findPrincipalNode(principalName, session);
221 if (!principalNode.hasNode(resourceTypeName)) {
222 log.debug("resource type {} is not set for principal {}", resourceTypeName, principalName);
223 return null;
224 }
225 Node node = principalNode.getNode(resourceTypeName);
226 for (PropertyIterator iter = node.getProperties(); iter.hasNext();) {
227 Property nodeData = iter.nextProperty();
228
229 try {
230 if (nodeData.getString().equals(nodeID)) {
231 nodeData.remove();
232
233 }
234 } catch (IllegalArgumentException e) {
235 log.debug("{} has invalid value", nodeData.getPath());
236 }
237 }
238 return null;
239 }});
240 }
241 }
242 catch (RepositoryException e) {
243 log.error("failed to remove " + resourceTypeName + " "+ resourceName + " from [" + principalName + "]", e);
244 }
245 }
246
247 protected abstract String getRepositoryName();
248
249 protected abstract Node findPrincipalNode(String principalName, Session session) throws RepositoryException;
250
251 public Map<String, ACL> getACLs(final String principalName) {
252 return MgnlContext.doInSystemContext(new SilentSessionOp<Map<String,ACL>>(getRepositoryName()) {
253 @Override
254 public Map<String, ACL> doExec(Session session) throws Throwable {
255 Node node = findPrincipalNode(principalName, session);
256 if(node == null){
257 return Collections.emptyMap();
258 }
259 return getACLs(node);
260 }});
261 }
262
263 protected Map<String, ACL> getACLs(Node node) throws RepositoryException, ValueFormatException, PathNotFoundException {
264 Map<String, ACL> principalList = new HashMap<String, ACL>();
265 NodeIterator it = new FilteringNodeIterator(node.getNodes(), new NodeTypePredicate(ItemType.CONTENTNODE.getSystemName(), true));
266 while (it.hasNext()) {
267 Node aclEntry = it.nextNode();
268 if (!aclEntry.getName().startsWith("acl")) {
269 continue;
270 }
271 String name = StringUtils.substringAfter(aclEntry.getName(), "acl_");
272
273 List<Permission> permissionList = new ArrayList<Permission>();
274
275 NodeIterator permissionIterator = new FilteringNodeIterator(aclEntry.getNodes(), new NodeTypePredicate(ItemType.CONTENTNODE.getSystemName(), true));
276 while (permissionIterator.hasNext()) {
277 Node map = permissionIterator.nextNode();
278 String path = map.getProperty("path").getString();
279 UrlPattern p = new SimpleUrlPattern(path);
280 Permission permission = new PermissionImpl();
281 permission.setPattern(p);
282 permission.setPermissions(map.getProperty("permissions").getLong());
283 permissionList.add(permission);
284 }
285
286 ACL acl;
287
288
289 if (principalList.containsKey(name)) {
290 acl = principalList.get(name);
291 permissionList.addAll(acl.getList());
292 }
293 acl = new ACLImpl(name, permissionList);
294 principalList.put(name, acl);
295
296 }
297 return principalList;
298 }
299
300 }