Redirect after Response has been written in Wicket 7.10 - response

We having a specific problem in using Wicket 7.10, creating an Ajax-Response with multiple entries.
In our application, we are using onRequestHandlerResolved to do some initialization stuff and onRequestHandlerExecuted to save changes done on our data during requestHandlerExecutor.execute().
For this purpose, we have created an own AbstractRequestCycleListener which overwrites both methods and calls our specific code.
RequestCycle:
private void execute(IRequestHandler handler)
{
try
{
listeners.onRequestHandlerResolved(this, handler);
requestHandlerExecutor.execute(handler);
listeners.onRequestHandlerExecuted(this, handler);
}
catch (RuntimeException e)
{
}
}
Our problem is, that an Exception thrown in onRequestHandlerExecuted after requestHandlerExecutor.execute() has already created an ajax-response creates an invalid response:
Wicket.Ajax: Wicket.Ajax.Call.failure: Error while parsing response: Error: Invalid XML:
<?xml version="1.0" encoding="UTF-8"?>
<ajax-response>
<!-- Result of requestHandlerExecutor.execute() -->
</ajax-response>
<ajax-response>
<!—Redirect to specific Exception Page, result of onRequestHandlerExecuted -->
<redirect>
<![CDATA[./wicket/bookmarkable/our.package.ExceptionPage?locale=en]]>
</redirect>
</ajax-response>
To solve our problem, we tried to clear the existing Response during Exception in onRequestHandlerExecuted (RequestCycle.get().getResponse().reset()), but we are not able to clear the Response, created in requestHandlerExecutor.execute(), because Wicket uses HeaderBufferingWebResponse by default which did not allow to reset already created Response in encapsulated ServletWebResponse. Calling reset in HeaderBufferingWebResponse instead throws an IllegalStateException.
We think that the problem came from ServletWebResponse which simply adds multiple ajax-response entries to the HttpServletResponse which results in the mentioned, invalid XML.
ServletWebResponse:
#Override
public void sendRedirect(String url)
{
try
{
if (webRequest.isAjax())
{
/*
* usually the Ajax-Location header is enough and we do not need to the redirect url
* into the response, but sometimes the response is processed via an iframe (eg
* using multipart ajax handling) and the headers are not available because XHR is
* not used and that is the only way javascript has access to response headers.
*/
httpServletResponse.getWriter().write(
"<ajax-response><redirect><![CDATA[" + url + "]]></redirect></ajax-response>");
}
else { }
}
catch (IOException e) { }
}
How we could handle the problem when throwing an Exception in onRequestHandlerExecuted? And how is it possible, that code run after requestHandlerExecutor.execute(), redirects correctly to an Exception page?
How we can run specific code, after the request has been processed, is there maybe another way instead of overwriting onRequestHandlerExecuted?

For each Ajax request Wicket executes two request handlers:
ListenerInterfaceRequestHandler
AjaxRequestHandler
I assume your #onRequestHandlerExecuted is failing after the second one. This might be too late since the response is already generated and written.
You could check:
why does your listener fail after anything else has happened already?
what do you want your application to do when your listener fails?
can't the listener fail after the first handler already? why wait any longer?

Related

Spring SAML - Handling Assertions

Our application in part of another enterprise application(Parent). Our application is invoked as a child application from parent Web App. The user comes authenticated(SSO) on the parent app. There user clicks on a link and our application is popped up. Requirement is that we handle SAML assertion and use the attributes that come as part of the assertion. My question is do I need to have full hierarachy of spring saml beans, or if I just have "webSSOprofileConsumer" which corresponds to WebSSOProfileConsumerImpl, is enough
We have a requirement of handling SAML assertions where we need not worry about SSO/Authentication. Is it possible to do that in Spring SAML integration? If yes how.
Thanks,
M
No, you don't need complete Spring SAML beans for this. You can do with OpenSAML only - it is sufficient for parsing of Assertion and extracting attributes (which seems to be the only thing you seem to need).
The following code is an example of converting XML stream with SAML message into SAML object:
protected T unmarshallMessage(Reader messageStream) throws MessageDecodingException {
log.debug("Parsing message stream into DOM document");
try {
Document messageDoc = getPool().parse(messageStream);
Element messageElem = messageDoc.getDocumentElement();
if (log.isTraceEnabled()) {
log.trace("Unmarshalled message into DOM:\n{}", XMLHelper.nodeToString(messageElem));
}
log.debug("Unmarshalling message DOM");
Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(messageElem);
if (unmarshaller == null) {
throw new MessageDecodingException(
"Unable to unmarshall message, no unmarshaller registered for message element "
+ XMLHelper.getNodeQName(messageElem));
}
T message = (T) unmarshaller.unmarshall(messageElem);
log.debug("Message successfully unmarshalled");
return message;
} catch (XMLParserException e) {
log.error("Encountered error parsing message into its DOM representation", e);
throw new MessageDecodingException("Encountered error parsing message into its DOM representation", e);
} catch (UnmarshallingException e) {
log.error("Encountered error unmarshalling message from its DOM representation", e);
throw new MessageDecodingException("Encountered error unmarshalling message from its DOM representation", e);
}
}
Call to getPool needs to return instance of org.opensaml.xml.parse.ParserPool, e.g. BasicParserPool.
The returned object will be e.g. of type org.opensaml.saml2.core.Response or org.opensaml.saml2.core.Assertion and you can find details of how to work with these objects in Spring SAML's codebase.
See e.g. SAMLCredential#getAttributeAsStringArray for details on handling of attributes.
You initialize OpenSAML by calling org.opensaml.DefaultBootstrap.bootstrap() during initialization of your application.

ASP.NET MVC 4: Handle exception caused by JsonValueProvider

I have an action that is called using requests with application/jsonin the Content-type header. These requests will automatically create a JsonValueProvider that tries to deserialize the request's content. When the json is malformed, the value provider will throw an exception leading to the application's error page.
To reproduce this behavior, simply POST invalid json data to an action sending application/json as the Content-type header. This will trigger the exception.
[Edit]
Not much code is needed. Simply create an empty controller method and use a tool like Firefox "Poster" to send an invalid request to the action.
public class HomeController
{
public ActionResult Index()
{
return this.Json(true);
}
}
Then use Poster:
Set Content-type to application/json
Set Request content to {"This is invalid JSON:,}
Send the request
The result will be the full-blown standard ASP.NET HTML error page (either generic or custom, depending on your application).
[/Edit]
Since my action is called by embedded devices, I would like to send short responses, instead of the HTML error page. I would like to be able to create a response with status code 500, Content-type: text/plain, and the exception's message as it's content.
I have already tried a custom model binder and a custom error handler attribute but neither are called since the exception occurs earlier on in the processing pipeline. Is there a way to handle this error?
As a workaround, I have currently disabled the JsonValueProvider for the whole application and load the values from the request body myself. If there is a way to disable the JsonValueProvider on a per action basis, this would also help.
Thanks in advance for any pointers!
You could subscribe to the Application_Error event in your Global.asax and handle the exception as you want:
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
Response.TrySkipIisCustomErrors = true;
Response.Clear();
Server.ClearError();
Response.StatusCode = 500;
Response.ContentType = "text/plain";
Response.Write("An error occured while processing your request. Details: " + exception.Message);
}

Generate PDF using Managed Bean with custom HTTP headers

Background
Generate a report in various formats (e.g., PDF, delimited, HTML) using an ADF Task Flow.
Problem
HTTP headers are being sent twice: once by the framework and once by a bean.
Source Code
The source code includes:
Button Action
Managed Bean
Task Flow
Button Action
The button action:
<af:commandButton text="Report" id="submitReport" action="Execute" />
Managed Bean
The Managed Bean is fairly complex. The code to responseComplete is getting called, however it does not seem to be called sufficiently early to prevent the application framework from writing the HTTP headers.
HTTP Response Header Override
/**
* Sets the HTTP headers required to indicate to the browser that the
* report is to be downloaded (rather than displayed in the current
* window).
*/
protected void setDownloadHeaders() {
HttpServletResponse response = getServletResponse();
response.setHeader( "Content-Description", getContentDescription() );
response.setHeader( "Content-Disposition", "attachment, filename="
+ getFilename() );
response.setHeader( "Content-Type", getContentType() );
response.setHeader( "Content-Transfer-Encoding",
getContentTransferEncoding() );
}
Issue Response Complete
getFacesContext().responseComplete();
Bean Run and Configure
public void run() {
try {
Report report = getReport();
configure(report.getParameters());
report.run();
} catch (Exception e) {
e.printStackTrace();
}
}
private void configure(Parameters p) {
p.put(ReportImpl.SYSTEM_REPORT_PROTOCOL, "http");
p.put(ReportImpl.SYSTEM_REPORT_HOST, "localhost");
p.put(ReportImpl.SYSTEM_REPORT_PORT, "7002");
p.put(ReportImpl.SYSTEM_REPORT_PATH, "/reports/rwservlet");
p.put(Parameters.PARAM_REPORT_FORMAT, "pdf");
p.put("report_cmdkey", getReportName());
p.put("report_ORACLE_1", getReportDestinationType());
p.put("report_ORACLE_2", getReportDestinationFormat());
}
Task Flow
The Task Flow calls Execute, which refers to the bean's run() method:
entry -> main -> Execute -> ReportBeanRun
Where:
<method-call id="ReportBeanRun">
<description>Executes a report</description>
<display-name>Execute Report</display-name>
<method>#{reportBean.run}</method>
<outcome>
<fixed-outcome>success</fixed-outcome>
</outcome>
</method-call>
The bean is assigned to the request scope, with a few managed properties:
<control-flow-rule id="__3">
<from-activity-id>main</from-activity-id>
<control-flow-case id="ExecuteReport">
<from-outcome>Execute</from-outcome>
<to-activity-id>ReportBeanRun</to-activity-id>
</control-flow-case>
</control-flow-rule>
<managed-bean id="ReportBean">
<description>Executes a report</description>
<display-name>ReportBean</display-name>
<managed-bean-scope>request</managed-bean-scope>
...
</managed-bean>
The <fixed-outcome>success</fixed-outcome> strikes me as incorrect -- I don't want the method call to return to another task.
Restrictions
The report server receives requests from the web server exclusively. The report server URL cannot be used by browsers to download directly, for security reasons.
Error Messages
The error message that is generated:
Duplicate headers received from server
Error 349 (net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION): Multiple distinct Content-Disposition headers received. This is disallowed to protect against HTTP response splitting attacks.
Nevertheless, the report is being generated. Preventing the framework from writing the HTTP headers would resolve this issue.
Question
How can you set the HTTP headers in ADF while using a Task Flow to generate a PDF by calling a managed bean?
Ideas
Some additional ideas:
Override the Page Lifecycle Phase Listener (ADFPhaseListener + PageLifecycle)
Develop a custom Servlet on the web server
Related Links
http://www.oracle.com/technetwork/middleware/bi-publisher/adf-bip-ucm-integration-179699.pdf
http://www.slideshare.net/lucbors/reports-no-notes#btnNext
http://www.techartifact.com/blogs/2012/03/calling-oracle-report-from-adf-applications.html?goback=%2Egde_4212375_member_102062735
http://docs.oracle.com/cd/E29049_01/web.1112/e16182/adf_lifecycle.htm#CIABEJFB
Thank you!
The problem was an incorrect implementation of RFC 2183:
response.setHeader( "Content-Disposition", "attachment; filename="
+ getFilename() );
The ; cannot be a ,.

Why is Phase Listener-based JSF redirect not working for AJAX requests when session has timed-out?

I have a JSF Phase Listerner that checks to see if the user is logged in, and if not, redirects them to the login page. This is working fine for non-ajax requests. However, if the user is on a page, in my case, one that has a primefaces data table, and clicks on a button that invokes an ajax request -- but their session has timed out -- the code gets executed that issues the redirect (using ExternalContext#redirect), however the user is not navigated to the login page.
Any idea why this is not working?
Here is my phase listener:
private static final String IS_LOGGED_IN_INDICATOR = "loggedIn";
private static final String LOGIN_PAGE = "/login.jsp";
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
public void beforePhase(PhaseEvent event) {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
HttpSession session = (HttpSession)ec.getSession(false);
if (session==null || session.getAttribute(IS_LOGGED_IN_INDICATOR) == null) {
try {
ec.redirect(LOGIN_PAGE);
}
catch(IOException e) {
// log exception...
}
}
}
public void afterPhase(PhaseEvent event) {
// no-op
}
}
It failed because the ajax context is trying to obtain the render kit from the view root, while there is no view root at all. It has not been restored at that point yet. This resulted in a NullPointerException in PartialViewContext#createPartialResponseWriter(). This exception is in turn not been thrown, but instead been put in an ajax exception queue which is supposed to be handled by a custom ExceptionHandler. You apparently don't have any one. This exception is visible if you create/use such one like the FullAjaxExceptionHandler (see also this blog for more detail).
To fix the particular problem, do the job in afterPhase() instead. The view root is then fully restored and the ajax context can obtain the render kit from it in order to write a specialized XML response which instructs the JSF ajax engine in JavaScript to change the window location. Without ajax, a render kit was not necessary as a redirect is basically just a matter of setting a response header.
Whether the particular NullPointerException is in turn a bug in Mojarra or not is a different question which can better be posted in flavor of an issue report at their own issue tracker.
this is because you have to send a special response in XML for Ajax request in order to do redirect (check this answer) , I have implemented this in a Filter like this..
// Check if it's an Ajax Request
if ("partial/ajax".equals(((HttpServletRequest) request).getHeader("Faces-Request"))) {
//redirect
response.setContentType("text/xml");
response.getWriter()
.append("<?xml version= \"1.0\" encoding=\"UTF-8\"?>")
.printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>",url);
you should port this to your Phase Listener.

Jsf2.0 preRenderView

i am using jsf 2.0
i have question accoring to PreRenderView.
in my Bean i have method like
public void init() throws Exception
{
FacesContext.getCurrentInstance().getExternalContext().redirect("/To My Page");
if(!FacesContext.getCurrentInstance().isPostback())
{
System.out.println("Kshitij");
}
}
when this method is executing it is also printing "Kshitij" in servler log.
then redirecting to page.
why? i think it has to redirect to page first.
Why do you think that the actual redirect is performed first? The method has to finish running first before the server can ever continue the control over the request/response. It's impossible to pause code execution halfway and then continue code execution at exactly the same location in a brand new request and thread.
The redirect() call basically sets the Location response header. Only when the method has returned, the server will send the response and then the browser will send a new request on that location.
Add a return statement or an if/else if you want to skip the printing when you need to redirect.
if (youNeedToRedirect) {
FacesContext.getCurrentInstance().getExternalContext().redirect("/To My Page");
}
else {
if (!FacesContext.getCurrentInstance().isPostback()) {
System.out.println("Kshitij");
}
}
This all has got nothing to do with JSF or preRenderView. It's all just basic Java and HTTP.
Related:
java.lang.IllegalStateException: Cannot (forward | sendRedirect | create session) after response has been committed

Resources