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.repository.RepositoryConstants;
44
45 import java.util.ArrayList;
46 import java.util.Collection;
47 import java.util.Collections;
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 } catch (ValueFormatException e) {
111 log.debug("{} has invalid value", property.getPath());
112 }
113 }
114 return list;
115 }
116 });
117
118
119
120 return MgnlContext.doInSystemContext(new JCRSessionOp<Boolean>(sessionName) {
121
122 @Override
123 public Boolean exec(Session session) throws RepositoryException {
124 for (String groupOrRole : groupsOrRoles) {
125
126 try {
127 if (session.getNodeByIdentifier(groupOrRole).getName().equalsIgnoreCase(resourceName)) {
128 return true;
129 }
130 } catch (RepositoryException e ) {
131 log.debug("Role [{}] does not exist in the ROLES repository", resourceName);
132 }
133 }
134 return false;
135 }});
136
137 } catch (RepositoryException e) {
138
139 log.debug(e.getMessage(), e);
140 } finally {
141 log.debug("checked {} for {} in {}ms.", new Object[] {resourceName, resourceTypeName, (System.currentTimeMillis() - start)});
142 }
143 return false;
144 }
145
146
147
148
149
150
151
152
153
154 protected void add(final String principalName, final String resourceName, final String resourceTypeName) throws PrincipalNotFoundException {
155 try {
156 final String nodeID = getLinkedResourceId(resourceName, resourceTypeName);
157
158 if (!hasAny(principalName, resourceName, resourceTypeName)) {
159 Session session = MgnlContext.getJCRSession(getRepositoryName());
160 Node principalNode = findPrincipalNode(principalName, session);
161 if (principalNode == null) {
162 throw new PrincipalNotFoundException("Principal " + principalName + " of type " + resourceTypeName + " was not found.");
163 }
164 if (!principalNode.hasNode(resourceTypeName)) {
165 principalNode.addNode(resourceTypeName, ItemType.CONTENTNODE.getSystemName());
166 }
167 Node node = principalNode.getNode(resourceTypeName);
168
169
170 String newName = Path.getUniqueLabel(session, node.getPath(), "0");
171 node.setProperty(newName, nodeID);
172 session.save();
173 }
174 }
175 catch (RepositoryException e) {
176 log.error("failed to add " + resourceTypeName + " "+ resourceName + " to [" + principalName + "]", e);
177 }
178 }
179
180 private String getLinkedResourceId(final String resourceName, final String resourceTypeName) throws AccessDeniedException {
181 final String nodeID;
182 if (StringUtils.equalsIgnoreCase(resourceTypeName, NODE_ROLES)) {
183 Role role = SecuritySupport.Factory.getInstance().getRoleManager().getRole(resourceName);
184 if (role == null) {
185 log.warn("Invalid role requested: {}", resourceName);
186 nodeID = null;
187 }
188 else {
189 nodeID = role.getId();
190 }
191 }
192 else {
193 Group group = SecuritySupport.Factory.getInstance().getGroupManager().getGroup(resourceName);
194 if (group == null) {
195 log.warn("Invalid group requested: {}", resourceName);
196 nodeID = null;
197 }
198 else {
199 nodeID = group.getId();
200 }
201 }
202 return nodeID;
203 }
204
205 protected String getResourceName(final String resourceId) {
206 try {
207 return MgnlContext.getJCRSession(getRepositoryName()).getNodeByIdentifier(resourceId).getName();
208 } catch (ItemNotFoundException e) {
209
210 return null;
211 }
212 catch (RepositoryException e) {
213 log.error(e.getMessage(), e);
214 }
215 return null;
216 }
217
218
219
220
221
222
223
224
225
226
227
228
229 protected void remove(final String principalName, final String resourceName, final String resourceTypeName) throws PrincipalNotFoundException {
230 try {
231 final String nodeID = getLinkedResourceId(resourceName, resourceTypeName);
232
233 if (hasAny(principalName, resourceName, resourceTypeName)) {
234 Session session = MgnlContext.getJCRSession(getRepositoryName());
235 Node principalNode = findPrincipalNode(principalName, session);
236 if (!principalNode.hasNode(resourceTypeName)) {
237 throw new PrincipalNotFoundException("Principal " + principalName + " of type " + resourceTypeName + " was not found.");
238 }
239 Node node = principalNode.getNode(resourceTypeName);
240 for (PropertyIterator iter = node.getProperties(); iter.hasNext();) {
241 Property nodeData = iter.nextProperty();
242
243 try {
244 if (nodeData.getString().equals(nodeID)) {
245 nodeData.remove();
246 session.save();
247
248 }
249 } catch (IllegalArgumentException e) {
250 log.debug("{} has invalid value", nodeData.getPath());
251 } catch (ValueFormatException e) {
252 log.debug("{} has invalid value", nodeData.getPath());
253 }
254 }
255 }
256 }
257 catch (RepositoryException e) {
258 log.error("failed to remove " + resourceTypeName + " "+ resourceName + " from [" + principalName + "]", e);
259 }
260 }
261
262 protected abstract String getRepositoryName();
263
264 protected abstract Node findPrincipalNode(String principalName, Session session) throws RepositoryException;
265
266 public Map<String, ACL> getACLs(final String principalName) {
267 return MgnlContext.doInSystemContext(new SilentSessionOp<Map<String,ACL>>(getRepositoryName()) {
268 @Override
269 public Map<String, ACL> doExec(Session session) throws Throwable {
270 Node node = findPrincipalNode(principalName, session);
271 if(node == null){
272 return Collections.emptyMap();
273 }
274 return getACLs(node);
275 }});
276 }
277
278 protected Map<String, ACL> getACLs(Node node) throws RepositoryException, ValueFormatException, PathNotFoundException {
279 Map<String, ACL> principalList = new HashMap<String, ACL>();
280 NodeIterator it = new FilteringNodeIterator(node.getNodes(), new NodeTypePredicate(ItemType.CONTENTNODE.getSystemName(), true));
281 while (it.hasNext()) {
282 Node aclEntry = it.nextNode();
283 if (!aclEntry.getName().startsWith("acl")) {
284 continue;
285 }
286 String name = StringUtils.substringAfter(aclEntry.getName(), "acl_");
287
288 List<Permission> permissionList = new ArrayList<Permission>();
289
290 NodeIterator permissionIterator = new FilteringNodeIterator(aclEntry.getNodes(), new NodeTypePredicate(ItemType.CONTENTNODE.getSystemName(), true));
291 while (permissionIterator.hasNext()) {
292 Node map = permissionIterator.nextNode();
293 String path = map.getProperty("path").getString();
294 UrlPattern p = new SimpleUrlPattern(path);
295 Permission permission = new PermissionImpl();
296 permission.setPattern(p);
297 permission.setPermissions(map.getProperty("permissions").getLong());
298 permissionList.add(permission);
299 }
300
301 ACL acl;
302
303
304 if (principalList.containsKey(name)) {
305 acl = principalList.get(name);
306 permissionList.addAll(acl.getList());
307 }
308 acl = new ACLImpl(name, permissionList);
309 principalList.put(name, acl);
310
311 }
312 return principalList;
313 }
314
315 }