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