1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
package org.apache.myfaces.lifecycle; |
20 | |
|
21 | |
import java.io.IOException; |
22 | |
import java.net.URI; |
23 | |
import java.net.URISyntaxException; |
24 | |
import java.util.logging.Level; |
25 | |
import java.util.logging.Logger; |
26 | |
|
27 | |
import javax.el.MethodExpression; |
28 | |
import javax.faces.FacesException; |
29 | |
import javax.faces.FactoryFinder; |
30 | |
import javax.faces.application.Application; |
31 | |
import javax.faces.application.ProjectStage; |
32 | |
import javax.faces.application.ProtectedViewException; |
33 | |
import javax.faces.application.ViewExpiredException; |
34 | |
import javax.faces.application.ViewHandler; |
35 | |
import javax.faces.component.UIViewRoot; |
36 | |
import javax.faces.context.ExternalContext; |
37 | |
import javax.faces.context.FacesContext; |
38 | |
import javax.faces.event.PhaseEvent; |
39 | |
import javax.faces.event.PhaseId; |
40 | |
import javax.faces.event.PostAddToViewEvent; |
41 | |
import javax.faces.flow.FlowHandler; |
42 | |
import javax.faces.lifecycle.ClientWindow; |
43 | |
import javax.faces.lifecycle.Lifecycle; |
44 | |
import javax.faces.lifecycle.LifecycleFactory; |
45 | |
import javax.faces.render.RenderKit; |
46 | |
import javax.faces.render.RenderKitFactory; |
47 | |
import javax.faces.render.ResponseStateManager; |
48 | |
import javax.faces.view.ViewDeclarationLanguage; |
49 | |
import javax.faces.view.ViewMetadata; |
50 | |
import javax.faces.webapp.FacesServlet; |
51 | |
import javax.servlet.http.HttpServletResponse; |
52 | |
import org.apache.myfaces.event.PostClientWindowAndViewInitializedEvent; |
53 | |
|
54 | |
import org.apache.myfaces.renderkit.ErrorPageWriter; |
55 | |
import org.apache.myfaces.shared.config.MyfacesConfig; |
56 | |
import org.apache.myfaces.shared.util.ExternalContextUtils; |
57 | |
import org.apache.myfaces.shared.util.ViewProtectionUtils; |
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | 0 | class RestoreViewExecutor extends PhaseExecutor |
67 | |
{ |
68 | |
|
69 | |
|
70 | 0 | private static final Logger log = Logger.getLogger(RestoreViewExecutor.class.getName()); |
71 | |
|
72 | |
private RestoreViewSupport _restoreViewSupport; |
73 | |
|
74 | |
private Boolean _viewNotFoundCheck; |
75 | |
|
76 | 0 | private RenderKitFactory _renderKitFactory = null; |
77 | |
|
78 | |
@Override |
79 | |
public void doPrePhaseActions(FacesContext facesContext) |
80 | |
{ |
81 | |
|
82 | |
|
83 | |
|
84 | |
|
85 | 0 | facesContext.getApplication().getViewHandler().initView(facesContext); |
86 | 0 | } |
87 | |
|
88 | |
public boolean execute(FacesContext facesContext) |
89 | |
{ |
90 | 0 | if (facesContext == null) |
91 | |
{ |
92 | 0 | throw new FacesException("FacesContext is null"); |
93 | |
} |
94 | |
|
95 | |
|
96 | 0 | Application application = facesContext.getApplication(); |
97 | 0 | ViewHandler viewHandler = application.getViewHandler(); |
98 | 0 | UIViewRoot viewRoot = facesContext.getViewRoot(); |
99 | 0 | RestoreViewSupport restoreViewSupport = getRestoreViewSupport(facesContext); |
100 | |
|
101 | |
|
102 | 0 | if (viewRoot != null) |
103 | |
{ |
104 | 0 | if (log.isLoggable(Level.FINEST)) |
105 | |
{ |
106 | 0 | log.finest("View already exists in the FacesContext"); |
107 | |
} |
108 | |
|
109 | |
|
110 | |
|
111 | 0 | viewRoot.setLocale(facesContext.getExternalContext().getRequestLocale()); |
112 | |
|
113 | 0 | restoreViewSupport.processComponentBinding(facesContext, viewRoot); |
114 | |
|
115 | |
|
116 | 0 | _invokeViewRootAfterPhaseListener(facesContext); |
117 | |
|
118 | 0 | return false; |
119 | |
} |
120 | |
|
121 | 0 | String viewId = restoreViewSupport.calculateViewId(facesContext); |
122 | |
|
123 | |
|
124 | |
|
125 | |
|
126 | |
|
127 | 0 | final boolean errorPageRequest = facesContext.getExternalContext().getRequestMap() |
128 | |
.get("javax.servlet.error.message") != null; |
129 | |
|
130 | |
|
131 | |
|
132 | 0 | if (!errorPageRequest && restoreViewSupport.isPostback(facesContext)) |
133 | |
{ |
134 | 0 | if (log.isLoggable(Level.FINEST)) |
135 | |
{ |
136 | 0 | log.finest("Request is a postback"); |
137 | |
} |
138 | |
|
139 | 0 | if (checkViewNotFound(facesContext)) |
140 | |
{ |
141 | 0 | String derivedViewId = viewHandler.deriveLogicalViewId(facesContext, viewId); |
142 | 0 | ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(facesContext, |
143 | |
derivedViewId); |
144 | |
|
145 | |
|
146 | |
|
147 | 0 | if (facesContext.getResponseComplete()) |
148 | |
{ |
149 | 0 | return true; |
150 | |
} |
151 | |
|
152 | 0 | if (vdl == null || derivedViewId == null) |
153 | |
{ |
154 | 0 | sendSourceNotFound(facesContext, viewId); |
155 | 0 | return true; |
156 | |
} |
157 | 0 | else if (!restoreViewSupport.checkViewExists(facesContext, derivedViewId)) |
158 | |
{ |
159 | 0 | sendSourceNotFound(facesContext, viewId); |
160 | 0 | return true; |
161 | |
} |
162 | |
} |
163 | |
|
164 | |
try |
165 | |
{ |
166 | 0 | facesContext.setProcessingEvents(false); |
167 | |
|
168 | |
|
169 | |
|
170 | 0 | viewRoot = viewHandler.restoreView(facesContext, viewId); |
171 | 0 | if (viewRoot == null) |
172 | |
{ |
173 | 0 | if (facesContext.getResponseComplete()) |
174 | |
{ |
175 | |
|
176 | |
|
177 | 0 | return true; |
178 | |
} |
179 | |
else |
180 | |
{ |
181 | |
|
182 | |
|
183 | 0 | throw new ViewExpiredException("No saved view state could be found for the view identifier: " |
184 | |
+ viewId, viewId); |
185 | |
} |
186 | |
} |
187 | |
|
188 | |
|
189 | 0 | if (viewRoot.isTransient()) |
190 | |
{ |
191 | 0 | checkViewProtection(facesContext, viewHandler, viewRoot.getViewId(), viewRoot); |
192 | |
} |
193 | |
|
194 | |
|
195 | 0 | facesContext.setViewRoot(viewRoot); |
196 | |
} |
197 | |
finally |
198 | |
{ |
199 | 0 | facesContext.setProcessingEvents(true); |
200 | 0 | } |
201 | |
|
202 | |
|
203 | |
|
204 | 0 | restoreViewSupport.processComponentBinding(facesContext, viewRoot); |
205 | |
|
206 | 0 | ClientWindow clientWindow = facesContext.getExternalContext().getClientWindow(); |
207 | 0 | if (clientWindow != null) |
208 | |
{ |
209 | |
|
210 | |
|
211 | |
|
212 | 0 | facesContext.getApplication().publishEvent(facesContext, PostClientWindowAndViewInitializedEvent.class, |
213 | |
clientWindow); |
214 | |
} |
215 | 0 | } |
216 | |
else |
217 | |
{ |
218 | 0 | if (log.isLoggable(Level.FINEST)) |
219 | |
{ |
220 | 0 | log.finest("Request is not a postback. New UIViewRoot will be created"); |
221 | |
} |
222 | |
|
223 | |
|
224 | |
|
225 | 0 | String logicalViewId = viewHandler.deriveLogicalViewId(facesContext, viewId); |
226 | 0 | ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(facesContext, logicalViewId); |
227 | |
|
228 | |
|
229 | |
|
230 | 0 | if (facesContext.getResponseComplete()) |
231 | |
{ |
232 | 0 | return true; |
233 | |
} |
234 | |
|
235 | 0 | if (checkViewNotFound(facesContext)) |
236 | |
{ |
237 | 0 | if (vdl == null || logicalViewId == null) |
238 | |
{ |
239 | 0 | sendSourceNotFound(facesContext, viewId); |
240 | 0 | return true; |
241 | |
} |
242 | 0 | else if (!restoreViewSupport.checkViewExists(facesContext, logicalViewId)) |
243 | |
{ |
244 | 0 | sendSourceNotFound(facesContext, viewId); |
245 | 0 | return true; |
246 | |
} |
247 | |
} |
248 | |
|
249 | 0 | if (vdl != null) |
250 | |
{ |
251 | 0 | ViewMetadata metadata = vdl.getViewMetadata(facesContext, viewId); |
252 | |
|
253 | 0 | if (metadata != null) |
254 | |
{ |
255 | 0 | viewRoot = metadata.createMetadataView(facesContext); |
256 | |
|
257 | 0 | if(facesContext.getResponseComplete()) |
258 | |
{ |
259 | |
|
260 | |
|
261 | 0 | return true; |
262 | |
} |
263 | |
} |
264 | |
|
265 | 0 | if (viewRoot == null) |
266 | |
{ |
267 | 0 | facesContext.renderResponse(); |
268 | |
} |
269 | 0 | else if (viewRoot != null && !ViewMetadata.hasMetadata(viewRoot)) |
270 | |
{ |
271 | 0 | facesContext.renderResponse(); |
272 | |
} |
273 | 0 | } |
274 | |
else |
275 | |
{ |
276 | |
|
277 | 0 | facesContext.renderResponse(); |
278 | |
} |
279 | |
|
280 | 0 | checkViewProtection(facesContext, viewHandler, logicalViewId, viewRoot); |
281 | |
|
282 | |
|
283 | |
|
284 | |
|
285 | 0 | if (viewRoot == null) |
286 | |
{ |
287 | |
|
288 | |
|
289 | 0 | viewRoot = viewHandler.createView(facesContext, viewId); |
290 | |
} |
291 | |
|
292 | 0 | if (viewRoot == null && facesContext.getResponseComplete()) |
293 | |
{ |
294 | |
|
295 | |
|
296 | 0 | return true; |
297 | |
} |
298 | |
|
299 | |
|
300 | |
|
301 | |
|
302 | |
|
303 | |
|
304 | |
|
305 | |
|
306 | 0 | facesContext.setViewRoot(viewRoot); |
307 | |
|
308 | 0 | ClientWindow clientWindow = facesContext.getExternalContext().getClientWindow(); |
309 | 0 | if (clientWindow != null) |
310 | |
{ |
311 | 0 | facesContext.getApplication().publishEvent(facesContext, PostClientWindowAndViewInitializedEvent.class, |
312 | |
clientWindow); |
313 | |
} |
314 | |
|
315 | 0 | FlowHandler flowHandler = facesContext.getApplication().getFlowHandler(); |
316 | 0 | if (flowHandler != null) |
317 | |
{ |
318 | 0 | flowHandler.clientWindowTransition(facesContext); |
319 | |
} |
320 | |
|
321 | |
|
322 | 0 | application.publishEvent(facesContext, PostAddToViewEvent.class, viewRoot); |
323 | |
} |
324 | |
|
325 | |
|
326 | |
|
327 | |
|
328 | 0 | if (errorPageRequest && facesContext.isProjectStage(ProjectStage.Development)) |
329 | |
{ |
330 | 0 | facesContext.getViewRoot().getViewMap() |
331 | |
.put(ErrorPageWriter.ERROR_PAGE_BEAN_KEY, new ErrorPageWriter.ErrorPageBean()); |
332 | |
} |
333 | |
|
334 | |
|
335 | 0 | _invokeViewRootAfterPhaseListener(facesContext); |
336 | |
|
337 | 0 | return false; |
338 | |
} |
339 | |
|
340 | |
private void checkViewProtection(FacesContext facesContext, ViewHandler viewHandler, |
341 | |
String viewId, UIViewRoot root) throws ProtectedViewException |
342 | |
{ |
343 | 0 | boolean valid = true; |
344 | 0 | if (ViewProtectionUtils.isViewProtected(facesContext, viewId)) |
345 | |
{ |
346 | |
|
347 | |
|
348 | |
|
349 | 0 | String token = (String) facesContext.getExternalContext().getRequestParameterMap().get( |
350 | |
ResponseStateManager.NON_POSTBACK_VIEW_TOKEN_PARAM); |
351 | 0 | if (token != null && token.length() > 0) |
352 | |
{ |
353 | 0 | String renderKitId = null; |
354 | 0 | if (root != null) |
355 | |
{ |
356 | 0 | renderKitId = root.getRenderKitId(); |
357 | |
} |
358 | 0 | if (renderKitId == null) |
359 | |
{ |
360 | 0 | renderKitId = viewHandler.calculateRenderKitId(facesContext); |
361 | |
} |
362 | 0 | RenderKit renderKit = getRenderKitFactory().getRenderKit(facesContext, renderKitId); |
363 | 0 | ResponseStateManager rsm = renderKit.getResponseStateManager(); |
364 | |
|
365 | 0 | String storedToken = rsm.getCryptographicallyStrongTokenFromSession(facesContext); |
366 | 0 | if (token.equals(storedToken)) |
367 | |
{ |
368 | 0 | if (!ExternalContextUtils.isPortlet(facesContext.getExternalContext())) |
369 | |
{ |
370 | |
|
371 | 0 | String referer = facesContext.getExternalContext(). |
372 | |
getRequestHeaderMap().get("Referer"); |
373 | 0 | if (referer != null) |
374 | |
{ |
375 | 0 | valid = valid && checkRefererOrOriginHeader( |
376 | |
facesContext, viewHandler, referer); |
377 | |
} |
378 | 0 | String origin = facesContext.getExternalContext(). |
379 | |
getRequestHeaderMap().get("Origin"); |
380 | 0 | if (valid && origin != null) |
381 | |
{ |
382 | 0 | valid = valid && checkRefererOrOriginHeader( |
383 | |
facesContext, viewHandler, origin); |
384 | |
} |
385 | 0 | } |
386 | |
} |
387 | |
else |
388 | |
{ |
389 | 0 | valid = false; |
390 | |
} |
391 | 0 | } |
392 | |
else |
393 | |
{ |
394 | 0 | valid = false; |
395 | |
} |
396 | |
} |
397 | 0 | if (!valid) |
398 | |
{ |
399 | 0 | throw new ProtectedViewException(); |
400 | |
} |
401 | 0 | } |
402 | |
|
403 | |
private boolean checkRefererOrOriginHeader(FacesContext facesContext, |
404 | |
ViewHandler viewHandler, String refererOrOrigin) |
405 | |
{ |
406 | |
try |
407 | |
{ |
408 | |
|
409 | 0 | ExternalContext ectx = facesContext.getExternalContext(); |
410 | 0 | URI refererURI = new URI(refererOrOrigin); |
411 | 0 | String path = refererURI.getPath(); |
412 | 0 | String appContextPath = ectx.getApplicationContextPath(); |
413 | 0 | if (refererURI.isAbsolute()) |
414 | |
{ |
415 | |
|
416 | 0 | String host = refererURI.getHost(); |
417 | 0 | int port = refererURI.getPort(); |
418 | 0 | String serverHost = ectx.getRequestServerName(); |
419 | 0 | int serverPort = ectx.getRequestServerPort(); |
420 | |
|
421 | 0 | boolean matchPort = true; |
422 | 0 | if (serverPort != -1 && port != -1) |
423 | |
{ |
424 | 0 | matchPort = (serverPort == port); |
425 | |
} |
426 | 0 | boolean isStrictJsf2OriginHeaderAppPath = |
427 | |
MyfacesConfig.getCurrentInstance(ectx).isStrictJsf2OriginHeaderAppPath(); |
428 | 0 | if (!path.equals("")) |
429 | |
{ |
430 | 0 | if (serverHost.equals(host) && matchPort && path.contains(appContextPath)) |
431 | |
{ |
432 | |
|
433 | |
} |
434 | |
else |
435 | |
{ |
436 | |
|
437 | 0 | return false; |
438 | |
} |
439 | |
} |
440 | |
else |
441 | |
{ |
442 | 0 | if (serverHost.equals(host) && matchPort && !isStrictJsf2OriginHeaderAppPath) |
443 | |
{ |
444 | |
|
445 | |
|
446 | |
|
447 | |
} |
448 | |
else |
449 | |
{ |
450 | |
|
451 | 0 | return false; |
452 | |
} |
453 | |
} |
454 | |
} |
455 | |
|
456 | 0 | int appContextPathIndex = appContextPath != null ? path.indexOf(appContextPath) : -1; |
457 | 0 | int servletPathIndex = -1; |
458 | 0 | int pathInfoIndex = -1; |
459 | 0 | if (ectx.getRequestServletPath() != null && ectx.getRequestPathInfo() != null) |
460 | |
{ |
461 | 0 | servletPathIndex = ectx.getRequestServletPath() != null ? |
462 | |
path.indexOf(ectx.getRequestServletPath(), |
463 | |
appContextPathIndex >= 0 ? appContextPathIndex : 0) : -1; |
464 | 0 | if (servletPathIndex != -1) |
465 | |
{ |
466 | 0 | pathInfoIndex = servletPathIndex + ectx.getRequestServletPath().length(); |
467 | |
} |
468 | |
} |
469 | |
else |
470 | |
{ |
471 | 0 | servletPathIndex = -1; |
472 | 0 | pathInfoIndex = (appContextPathIndex >= 0 ? appContextPathIndex : 0) + appContextPath.length(); |
473 | |
} |
474 | |
|
475 | |
|
476 | 0 | if ((appContextPath == null || appContextPathIndex >= 0) && |
477 | |
(servletPathIndex >= 0 || pathInfoIndex >= 0)) |
478 | |
{ |
479 | |
String refererViewId; |
480 | 0 | if (pathInfoIndex >= 0) |
481 | |
{ |
482 | 0 | refererViewId = path.substring(pathInfoIndex); |
483 | |
} |
484 | |
else |
485 | |
{ |
486 | 0 | refererViewId = path.substring(servletPathIndex); |
487 | |
} |
488 | |
|
489 | 0 | String logicalViewId = viewHandler.deriveViewId(facesContext, refererViewId); |
490 | |
|
491 | |
|
492 | |
|
493 | |
|
494 | |
|
495 | |
|
496 | |
|
497 | |
|
498 | |
|
499 | |
|
500 | 0 | if (logicalViewId != null) |
501 | |
{ |
502 | 0 | return true; |
503 | |
} |
504 | |
else |
505 | |
{ |
506 | |
|
507 | |
} |
508 | |
} |
509 | 0 | return true; |
510 | |
} |
511 | 0 | catch (URISyntaxException ex) |
512 | |
{ |
513 | 0 | return false; |
514 | |
} |
515 | |
} |
516 | |
|
517 | |
|
518 | |
|
519 | |
|
520 | |
|
521 | |
|
522 | |
|
523 | |
|
524 | |
|
525 | |
private void _invokeViewRootAfterPhaseListener(FacesContext facesContext) |
526 | |
{ |
527 | |
|
528 | 0 | UIViewRoot root = facesContext.getViewRoot(); |
529 | 0 | MethodExpression afterPhaseExpression = root.getAfterPhaseListener(); |
530 | 0 | if (afterPhaseExpression != null) |
531 | |
{ |
532 | 0 | PhaseEvent event = new PhaseEvent(facesContext, getPhase(), _getLifecycle(facesContext)); |
533 | |
try |
534 | |
{ |
535 | 0 | afterPhaseExpression.invoke(facesContext.getELContext(), new Object[] { event }); |
536 | |
} |
537 | 0 | catch (Throwable t) |
538 | |
{ |
539 | 0 | log.log(Level.SEVERE, "An Exception occured while processing " + |
540 | |
afterPhaseExpression.getExpressionString() + |
541 | |
" in Phase " + getPhase(), t); |
542 | 0 | } |
543 | |
} |
544 | 0 | } |
545 | |
|
546 | |
|
547 | |
|
548 | |
|
549 | |
|
550 | |
|
551 | |
private Lifecycle _getLifecycle(FacesContext facesContext) |
552 | |
{ |
553 | 0 | LifecycleFactory factory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); |
554 | 0 | String id = facesContext.getExternalContext().getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR); |
555 | 0 | if (id == null) |
556 | |
{ |
557 | 0 | id = LifecycleFactory.DEFAULT_LIFECYCLE; |
558 | |
} |
559 | 0 | return factory.getLifecycle(id); |
560 | |
} |
561 | |
|
562 | |
protected RestoreViewSupport getRestoreViewSupport() |
563 | |
{ |
564 | 0 | return getRestoreViewSupport(FacesContext.getCurrentInstance()); |
565 | |
} |
566 | |
|
567 | |
protected RestoreViewSupport getRestoreViewSupport(FacesContext context) |
568 | |
{ |
569 | 0 | if (_restoreViewSupport == null) |
570 | |
{ |
571 | 0 | _restoreViewSupport = new DefaultRestoreViewSupport(context); |
572 | |
} |
573 | 0 | return _restoreViewSupport; |
574 | |
} |
575 | |
|
576 | |
protected RenderKitFactory getRenderKitFactory() |
577 | |
{ |
578 | 0 | if (_renderKitFactory == null) |
579 | |
{ |
580 | 0 | _renderKitFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); |
581 | |
} |
582 | 0 | return _renderKitFactory; |
583 | |
} |
584 | |
|
585 | |
|
586 | |
|
587 | |
|
588 | |
|
589 | |
public void setRestoreViewSupport(RestoreViewSupport restoreViewSupport) |
590 | |
{ |
591 | 0 | _restoreViewSupport = restoreViewSupport; |
592 | 0 | } |
593 | |
|
594 | |
public PhaseId getPhase() |
595 | |
{ |
596 | 0 | return PhaseId.RESTORE_VIEW; |
597 | |
} |
598 | |
|
599 | |
protected boolean checkViewNotFound(FacesContext facesContext) |
600 | |
{ |
601 | 0 | if (_viewNotFoundCheck == null) |
602 | |
{ |
603 | |
|
604 | 0 | _viewNotFoundCheck = MyfacesConfig.getCurrentInstance( |
605 | |
facesContext.getExternalContext()).isStrictJsf2ViewNotFound(); |
606 | |
} |
607 | 0 | return _viewNotFoundCheck; |
608 | |
} |
609 | |
|
610 | |
private void sendSourceNotFound(FacesContext context, String message) |
611 | |
{ |
612 | 0 | HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse(); |
613 | |
try |
614 | |
{ |
615 | 0 | context.responseComplete(); |
616 | 0 | response.sendError(HttpServletResponse.SC_NOT_FOUND, message); |
617 | |
} |
618 | 0 | catch (IOException ioe) |
619 | |
{ |
620 | 0 | throw new FacesException(ioe); |
621 | 0 | } |
622 | 0 | } |
623 | |
} |