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