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.filters;
35
36 import info.magnolia.cms.beans.runtime.File;
37 import info.magnolia.cms.beans.runtime.FileProperties;
38 import info.magnolia.cms.core.AggregationState;
39 import info.magnolia.cms.core.version.VersionManager;
40 import info.magnolia.cms.core.version.VersionedNode;
41 import info.magnolia.context.WebContext;
42 import info.magnolia.jcr.util.NodeTypes;
43 import info.magnolia.objectfactory.Components;
44
45 import java.io.IOException;
46
47 import javax.inject.Inject;
48 import javax.inject.Provider;
49 import javax.jcr.AccessDeniedException;
50 import javax.jcr.Node;
51 import javax.jcr.PathNotFoundException;
52 import javax.jcr.RepositoryException;
53 import javax.jcr.Session;
54 import javax.jcr.version.VersionException;
55 import javax.jcr.version.VersionHistory;
56 import javax.servlet.FilterChain;
57 import javax.servlet.ServletException;
58 import javax.servlet.http.HttpServletRequest;
59 import javax.servlet.http.HttpServletResponse;
60
61 import org.apache.commons.lang3.StringUtils;
62 import org.apache.jackrabbit.JcrConstants;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66
67
68
69
70 public class AggregatorFilter extends AbstractMgnlFilter {
71 private static final Logger log = LoggerFactory.getLogger(AggregatorFilter.class);
72
73 private final String VERSION_NUMBER = "mgnlVersion";
74
75 private final Provider<WebContext> contextProvider;
76
77 private final VersionManager versionManager;
78
79 @Inject
80 public AggregatorFilter(Provider<WebContext> contextProvider, VersionManager versionManager) {
81 this.contextProvider = contextProvider;
82 this.versionManager = versionManager;
83 }
84
85
86
87
88 @Deprecated
89 public AggregatorFilter() {
90 this(() -> Components.getComponent(WebContext.class), Components.getComponent(VersionManager.class));
91 }
92
93 @Override
94 public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
95
96 boolean success;
97 try {
98 success = collect();
99 } catch (AccessDeniedException e) {
100
101 log.debug(e.getMessage(), e);
102 if (!response.isCommitted()) {
103 response.setStatus(HttpServletResponse.SC_FORBIDDEN);
104 }
105
106 return;
107 } catch (RepositoryException e) {
108 log.error(e.getMessage(), e);
109 throw new ServletException(e.getMessage(), e);
110 }
111
112 if (!success) {
113 log.debug("Resource not found, redirecting request for [{}] to 404 URI", request.getRequestURI());
114
115 if (!response.isCommitted()) {
116 response.sendError(HttpServletResponse.SC_NOT_FOUND);
117 } else {
118 log.info("Unable to redirect to 404 page, response is already committed. URI was {}", request.getRequestURI());
119 }
120
121 return;
122 }
123 chain.doFilter(request, response);
124 }
125
126
127
128
129 protected boolean collect() throws RepositoryException {
130 final AggregationState aggregationState = contextProvider.get().getAggregationState();
131 final String handle = aggregationState.getHandle();
132 final String repository = aggregationState.getRepository();
133
134 final Session session = contextProvider.get().getJCRSession(repository);
135
136 Node requestedPage = null;
137 Node requestedData = null;
138 String templateName;
139
140 if (!isJcrPathValid(handle)) {
141 return false;
142 }
143 if (session.nodeExists(handle) && !hasBinarySubnode(session, handle)) {
144 requestedPage = session.getNode(handle);
145
146
147 final String versionNumber = contextProvider.get().getAttribute(VERSION_NUMBER);
148 if (versionNumber != null) {
149 try {
150 VersionHistory versionHistory = versionManager.getVersionHistory(requestedPage);
151 if (versionHistory != null) {
152 requestedPage = new VersionedNode(versionHistory.getVersion(versionNumber), requestedPage);
153 }
154 } catch (VersionException e) {
155 log.warn("The version '{}' of the node '{}' doesn't exists, rendering current state.", versionNumber, requestedPage, e);
156 } catch (RepositoryException re) {
157 log.debug(re.getMessage(), re);
158 log.error("Unable to get versioned state {} of {}, rendering current state.", versionNumber, handle);
159 }
160 }
161
162 try {
163 templateName = NodeTypes.Renderable.getTemplate(requestedPage);
164 } catch (RepositoryException e) {
165 templateName = null;
166 }
167
168 if (StringUtils.isBlank(templateName)) {
169 log.error("No template configured for page [{}].", requestedPage);
170 }
171 } else {
172 if (session.nodeExists(handle)) {
173 requestedData = session.getNode(handle);
174 } else {
175
176 int lastIndexOfSlash = handle.lastIndexOf("/");
177
178 if (lastIndexOfSlash > 0) {
179
180 final String handleToUse = StringUtils.substringBeforeLast(handle, "/");
181
182 try {
183 requestedData = session.getNode(handleToUse);
184 aggregationState.setHandle(handleToUse);
185
186
187
188
189 } catch (PathNotFoundException e) {
190
191 return false;
192 } catch (RepositoryException e) {
193 log.debug(e.getMessage(), e);
194 return false;
195 }
196 }
197 }
198
199 if (requestedData != null) {
200 templateName = requestedData.hasProperty(FileProperties.PROPERTY_TEMPLATE) ? requestedData.getProperty(FileProperties.PROPERTY_TEMPLATE).getString() : StringUtils.EMPTY;
201 } else {
202 return false;
203 }
204 }
205
206
207 if (requestedPage != null) {
208 aggregationState.setMainContentNode(requestedPage);
209 aggregationState.setCurrentContentNode(requestedPage);
210 }
211 if (requestedData != null && isBinary(requestedData)) {
212 File file = new File(requestedData);
213 aggregationState.setFile(file);
214 }
215
216 aggregationState.setTemplateName(templateName);
217
218 return true;
219 }
220
221 private boolean isBinary(Node requestedData) throws RepositoryException {
222 return requestedData.isNodeType(NodeTypes.Resource.NAME) ||
223 (requestedData.hasProperty("jcr:frozenPrimaryType") && requestedData.getProperty("jcr:frozenPrimaryType").getValue().getString().equals(NodeTypes.Resource.NAME));
224 }
225
226 private boolean hasBinarySubnode(Session session, String nodePath) throws RepositoryException {
227 return session.itemExists(nodePath + (nodePath.endsWith("/") ? "" : "/") + JcrConstants.JCR_DATA);
228 }
229
230
231
232
233
234
235
236 private boolean isJcrPathValid(String handle) {
237 if (StringUtils.isBlank(handle) || StringUtils.equals(handle, "/")) {
238
239 return false;
240 }
241 if (StringUtils.containsAny(handle, ':', '*', '\n')) {
242
243 return false;
244 }
245 if (StringUtils.contains(handle, " /")) {
246
247 return false;
248 }
249 return true;
250 }
251
252 }