我正在开发基于SAML 2.0的单点登录Apache Tomcat阀门。在测试我的实现时,我会发现以下一组错误,这些错误似乎是间歇性地发生在通过阀门的某些请求中。
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.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.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$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:393)
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:426)
at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:342)
at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:317)
at org.apache.catalina.connector.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.SocketChannelImpl.write(SocketChannelImpl.java:471)
at org.apache.tomcat.util.net.NioChannel.write(NioChannel.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.InternalNioOutputBuffer.writeToSocket(InternalNioOutputBuffer.java:139)
at org.apache.coyote.http11.InternalNioOutputBuffer.addToBB(InternalNioOutputBuffer.java:197)
at org.apache.coyote.http11.InternalNioOutputBuffer.access$000(InternalNioOutputBuffer.java:41)
at org.apache.coyote.http11.InternalNioOutputBuffer$SocketOutputBuffer.doWrite(InternalNioOutputBuffer.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.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:388)
... 17 more
这似乎发生在我编写HTML有效内容时,其中包含要发送的SAML 2.0请求内容。用于上述情况的代码如下:
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);
}
}
}
sendCharacterData方法将有效负载写入响应主体。
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);
}
}
大多数资源提供的解决方案似乎没有提供任何帮助。任何有关此场景的帮助都将受到高度赞赏。