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.security.setup.migration;
35
36 import info.magnolia.cms.util.PathUtil;
37 import info.magnolia.jcr.predicate.NodeNamePredicate;
38 import info.magnolia.jcr.predicate.NodePropertyNamePredicate;
39 import info.magnolia.jcr.util.NodeUtil;
40 import info.magnolia.module.InstallContext;
41 import info.magnolia.module.delta.AbstractRepositoryTask;
42 import info.magnolia.module.delta.TaskExecutionException;
43 import info.magnolia.repository.RepositoryConstants;
44
45 import java.util.ArrayList;
46 import java.util.Iterator;
47 import java.util.List;
48
49 import javax.jcr.Node;
50 import javax.jcr.Property;
51 import javax.jcr.RepositoryException;
52 import javax.jcr.Session;
53
54 import org.apache.commons.lang3.StringUtils;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58
59
60
61
62
63
64
65
66
67
68
69 public class MoveAclPermissionsBetweenWorkspaces extends AbstractRepositoryTask {
70
71 private static final Logger log = LoggerFactory.getLogger(MoveAclPermissionsBetweenWorkspaces.class);
72
73 private String everythingUnderThis = "/*";
74 private String SelectedNode = "$";
75
76 private final List<String> subPaths;
77 private final String sourceWorkspaceName;
78 private final String targetWorkspaceName;
79 private final boolean updatePath;
80
81
82
83
84
85
86 public MoveAclPermissionsBetweenWorkspaces(String name, String description, String sourceWorkspaceName, String targetWorkspaceName, List<String> subPaths, boolean updatePath) {
87 super(name, description);
88 this.sourceWorkspaceName = sourceWorkspaceName;
89 this.targetWorkspaceName = targetWorkspaceName;
90 this.updatePath = updatePath;
91 this.subPaths = subPaths == null ? new ArrayList<String>() : subPaths;
92 }
93
94
95 @Override
96 protected void doExecute(InstallContext installContext) throws RepositoryException, TaskExecutionException {
97 if (StringUtils.isBlank(this.sourceWorkspaceName) || StringUtils.isBlank(this.targetWorkspaceName)) {
98 log.warn("sourceWorkspaceName:'{}' and targetWorkspaceName:'{}' have to be defined ", this.sourceWorkspaceName, this.targetWorkspaceName);
99 return;
100 }
101
102 final Session targetSession = installContext.getJCRSession(targetWorkspaceName);
103 final Session session = installContext.getJCRSession(RepositoryConstants.USER_ROLES);
104 final Node rootNode = session.getRootNode();
105
106 String nodeName = "acl_" + sourceWorkspaceName;
107 String newAclNodeName = "acl_" + targetWorkspaceName;
108 Iterator<Node> iterator = NodeUtil.collectAllChildren(rootNode, new NodeNamePredicate(nodeName)).iterator();
109 while (iterator.hasNext()) {
110 Node aclNode = iterator.next();
111 handleAclNode(targetSession, aclNode, newAclNodeName, installContext);
112 }
113 }
114
115
116
117
118 private void handleAclNode(Session targetSession, Node aclNode, String newAclNodeName, InstallContext installContext) throws RepositoryException {
119
120 final Node parent = aclNode.getParent();
121 final String newAclPath = NodeUtil.combinePathAndName(parent.getPath(), newAclNodeName);
122 if (aclNode.getSession().nodeExists(newAclPath)) {
123 log.warn("{} already exist. No migration will be performed.", newAclPath);
124 return;
125 }
126
127
128 String oldAclNodePath = aclNode.getPath();
129 NodeUtil.renameNode(aclNode, newAclNodeName);
130 log.info("The following ACL node '{}' was succesfully renamed to '{}'", oldAclNodePath, aclNode.getPath());
131
132 Iterator<Node> childNodeIterator = NodeUtil.collectAllChildren(aclNode, new NodePropertyNamePredicate("path")).iterator();
133
134 while (childNodeIterator.hasNext()) {
135 Property pathProperty = childNodeIterator.next().getProperty("path");
136 String originalPath = pathProperty.getString();
137 String extraParameter = getExtraAclParameter(originalPath);
138 String pathToHandle = StringUtils.removeEnd(originalPath, extraParameter);
139
140 if (StringUtils.isBlank(pathToHandle)) {
141 continue;
142 }
143
144
145 if (!isPathWellFormed(targetSession, pathToHandle)) {
146 log.info("Following ACL link is not a well-formed path '{}'. ", originalPath);
147 } else if (!targetSession.itemExists(pathToHandle)) {
148
149 handleNoNoValidACLPath(targetSession, pathToHandle, extraParameter, pathProperty, installContext);
150 } else {
151 log.info("Following ACL link is valid '{}'. ", originalPath);
152 }
153 }
154 }
155
156
157
158
159 private boolean isPathWellFormed(Session targetSession, String path) {
160 try {
161 targetSession.itemExists(path);
162 return true;
163 } catch (RepositoryException e) {
164 return false;
165 }
166 }
167
168
169
170
171 private void handleNoNoValidACLPath(Session targetSession, String originalPath, String extraParameter, Property pathProperty, InstallContext installContext) throws RepositoryException {
172
173 String validPath = getValidPathWithSubPath(targetSession, originalPath);
174 if (StringUtils.isNotBlank(validPath)) {
175 if (this.updatePath) {
176
177 validPath = validPath + extraParameter;
178 pathProperty.setValue(validPath);
179 log.info("The original path was incorect '{}' and is replaced by '{}'", originalPath, validPath);
180 } else {
181 installContext.info("The path '" + originalPath + "' defined for the following ACL '" + pathProperty.getParent().getPath() + "' is no more valid. The following is Valid '" + validPath + "'. Please use Security App to correct this.");
182 }
183 } else {
184 installContext.warn("The path '" + originalPath + "' defined for the following ACL '" + pathProperty.getParent().getPath() + "' is no more valid. Please use Security App to correct this.");
185 log.warn("The path '{}' defined for the following ACL '{}' is no more valid. Please use Security App to correct this.", originalPath, pathProperty.getParent().getPath());
186
187 }
188 }
189
190
191
192
193
194
195 private String getValidPathWithSubPath(Session targetSession, String originalPath) throws RepositoryException {
196 for (String subPath : subPaths) {
197 String migratedPath = PathUtil.createPath(StringUtils.removeEnd(subPath, "/"), StringUtils.removeStart(originalPath, "/"));
198 log.debug("Check if the following migrated path exist {}", migratedPath);
199 if (targetSession.itemExists(migratedPath)) {
200 return migratedPath;
201 }
202 }
203 return null;
204 }
205
206 private String getExtraAclParameter(String acl) {
207 if (StringUtils.endsWith(acl, everythingUnderThis)) {
208 return everythingUnderThis;
209 }
210 if (StringUtils.endsWith(acl, SelectedNode)) {
211 return SelectedNode;
212 }
213 return StringUtils.EMPTY;
214 }
215
216 }