BalusC commented on PR #2930:
URL: https://github.com/apache/shiro/pull/2930#issuecomment-6425403174

   Nice. The gate looks right: the view is only rebuilt for a 
`FormResubmitRequest`, and that request only exists after the same-origin 
checks. So a forged or cross-site postback cannot trigger a rebuild.
   
   A few points.
   
   ### M1. On MyFaces, a rebuilt Ajax view is not re-rendered with `@all`
   
   `replaySavedForm` still computes `isStateless` with `isJSFStatefulForm`, and 
that still uses the Mojarra pattern `-?\d+:-?\d+`. The MyFaces server-side 
token is Base64, so it never matches, and the form counts as stateless. The 
view handler rebuilds the view anyway, because it does not check `isStateless`. 
But `AjaxReplay.forForm(isPartial, true)` downgrades `RENDER_ALL` to 
`PASS_THROUGH`. So on MyFaces an Ajax replay renders only the form's own 
targets, on a view that was built from scratch. The other forms on the page 
keep their expired view state. I did not run this on MyFaces; it follows from 
the code.
   
   **Fix:** in `isJSFStatefulForm`, treat any non-blank view state other than 
the literal `stateless` as stateful. Both Mojarra and MyFaces use `stateless` 
for a stateless view. Add a unit test with a MyFaces-style Base64 token.
   
   ### m2. The view is built while Faces events are off
   
   Restore View calls `setProcessingEvents(false)` before `restoreView`, in 
Mojarra and in MyFaces. So `ComponentsLocal.buildView` runs without 
`PostAddToViewEvent`. Things like `f:event type="postAddToView"` and the 
relocation of `h:outputScript target="head"` depend on it. Mojarra turns events 
on for its own rebuild of a stateless view (`FaceletViewHandlingStrategy`). 
This matters most when the response renders `@all`.
   
   **Fix:** call `context.setProcessingEvents(true)` around `buildView`, and 
restore the previous value in a `finally`.
   
   ### m3. The reason in the `noJSFAjaxRequests` javadoc no longer holds
   
   It says the Ajax fields are only kept for stateless views, because there 
they cannot fail view state restoration. With the view handler, a lost stateful 
view is rebuilt, so it cannot fail restoration either. The stateless/stateful 
split still changes behavior: it decides whether the replay executes the whole 
form or only the partial execute.
   
   **Fix:** decide if the split is still wanted. If yes, rewrite the javadoc 
with the reason that still holds. If no, keep the Ajax fields for both.
   
   ### n4. Unrelated change in `FormSupportTest`
   
   `parseFormDataHonoursCharset` replaces the `ö` escapes with a literal `ö`. 
This is not related to #2931, and the test now depends on the source file 
encoding.
   
   **Fix:** revert those two lines.
   
   ### n5. `@SneakyThrows(IOException.class)` on `restoreView`
   
   This throws a checked exception from a method that does not declare it. 
Wrapping it in a `FacesException` is the usual way, and then the application's 
`ExceptionHandler` handles it normally.
   
   **Fix:** catch the `IOException` and throw `new FacesException(e)`. Update 
`buildFailurePropagatesToReplayFallback` to expect that.
   
   ### Possible follow-up: drop the in-place replay
   
   With this view handler in place, `ShiroFilter` does not need to read the 
body and dispatch it a second time for an expired same-origin form. It can mark 
the request in `createSubject` (after the same-origin check), let it continue 
down the normal filter chain, and let the view handler rebuild the view for 
marked requests. That would:
   
   - keep the request body readable for non-Faces endpoints, such as a servlet 
that calls `getInputStream()` (today it gets a redirect, because the body was 
already consumed);
   - run the remaining filters in the chain once, in the normal order;
   - remove the unbounded read of the request body into memory.
   
   The after-login replay would stay as it is.
   
   🤖 Generated with Claude Opus 5.5


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to