I am working on a SAML 2.0 based single-sign-on, Apache Tomcat valve. When testing my implementation I cam across the following set of errors which seem to occur intermittently to certain requests passed through the valve.
28-Apr-2016 23:29:50.798 SEVERE [http-nio-8080-exec-1] org.wso2.appserver.webapp.security.saml.SAMLSingleSignOn.invoke An error has occurred when processing the request
org.wso2.appserver.webapp.security.utils.SSOException: Error occurred while writing to HttpServletResponse
at org.wso2.appserver.webapp.security.saml.SAMLSSOManager.sendCharacterData(SAMLSSOManager.java:299)
at org.wso2.appserver.webapp.security.saml.SAMLSingleSignOn.handleUnauthenticatedRequest(SAMLSingleSignOn.java:212)
at org.wso2.appserver.webapp.security.saml.SAMLSingleSignOn.invoke(SAMLSingleSignOn.java:127)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.coector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractCoectionHandler.process(AbstractProtocol.java:673)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRuable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.catalina.coector.ClientAbortException: java.io.IOException: Broken pipe
at org.apache.catalina.coector.OutputBuffer.realWriteBytes(OutputBuffer.java:393)
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:426)
at org.apache.catalina.coector.OutputBuffer.doFlush(OutputBuffer.java:342)
at org.apache.catalina.coector.OutputBuffer.flush(OutputBuffer.java:317)
at org.apache.catalina.coector.Response.flushBuffer(Response.java:510)
at org.wso2.appserver.webapp.security.saml.SAMLSSOManager.sendCharacterData(SAMLSSOManager.java:296)
... 12 more
Caused by: java.io.IOException: Broken pipe
at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
at sun.nio.ch.IOUtil.write(IOUtil.java:65)
at sun.nio.ch.SocketChaelImpl.write(SocketChaelImpl.java:471)
at org.apache.tomcat.util.net.NioChael.write(NioChael.java:124)
at org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:101)
at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:172)
at org.apache.coyote.http11.IntealNioOutputBuffer.writeToSocket(IntealNioOutputBuffer.java:139)
at org.apache.coyote.http11.IntealNioOutputBuffer.addToBB(IntealNioOutputBuffer.java:197)
at org.apache.coyote.http11.IntealNioOutputBuffer.access$000(IntealNioOutputBuffer.java:41)
at org.apache.coyote.http11.IntealNioOutputBuffer$SocketOutputBuffer.doWrite(IntealNioOutputBuffer.java:320)
at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:116)
at org.apache.coyote.http11.AbstractOutputBuffer.doWrite(AbstractOutputBuffer.java:256)
at org.apache.coyote.Response.doWrite(Response.java:501)
at org.apache.catalina.coector.OutputBuffer.realWriteBytes(OutputBuffer.java:388)
... 17 more
This seems to occur when I write the HTML payload, which contains the SAML 2.0 request content to be sent. The code used for the above case is as follows:
private void handleUnauthenticatedRequest(Request request, Response response,
SSOAgentRequestResolver requestResolver) throws SSOException {
SAMLSSOManager manager = new SAMLSSOManager(agentConfiguration);
// handle the generation of the SAML 2.0 RelayState
String relayStateId = SSOUtils.createID();
RelayState relayState = SSOUtils.generateRelayState(request);
if (agentConfiguration != null) {
agentConfiguration.getSAML2().setRelayState(relayStateId);
}
Optional.ofNullable(request.getSession(false))
.ifPresent(httpSession -> httpSession.setAttribute(relayStateId, relayState));
// TODO: check if the isPassive option of wso2as-web.xml can be removed since this is overridden here + usage
Optional.ofNullable(agentConfiguration)
.ifPresent(agent -> agent.getSAML2().enablePassiveAuthenticationEnabled(false));
if (requestResolver.isHttpPOSTBinding()) {
containerLog.info("Handling the SAML 2.0 Authentication Request for HTTP-POST binding...");
String htmlPayload = manager.handleAuthnRequestForPOSTBinding(request);
manager.sendCharacterData(response, htmlPayload);
} else {
containerLog.info("Handling the SAML 2.0 Authentication Request for " +
agentConfiguration.getSAML2().getHttpBinding() + "...");
try {
response.sendRedirect(manager.handleAuthnRequestForRedirectBinding(request));
} catch (IOException e) {
throw new SSOException("Error when handling SAML 2.0 HTTP-Redirect binding", e);
}
}
}
The method sendCharacterData writes the payload to the response body.
protected void sendCharacterData(HttpServletResponse response, String htmlPayload) throws SSOException {
try {
Writer writer = response.getWriter();
writer.write(htmlPayload);
response.flushBuffer();
// not closing the Writer instance, as its creator is the HttpServletResponse
} catch (IOException e) {
throw new SSOException("Error occurred while writing to HttpServletResponse", e);
}
}
The solutions provided in most resources do not seem to provide any help. Any help with this scenario will be highly appreciated.
