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