<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body> <s:Fault> <faultcode xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">a:InvalidSecurity</faultcode> <faultstring xml:lang="pl-PL">An error occurred when verifying security for the message.</faultstring> </s:Fault> </s:Body> </s:Envelope>
WCF zakłada określoną kolejność elementów nagłówka
Z pomocą przychodzi mechanizm interceptorów w Apache CXF, dzięki któremu możliwa jest modyfikacja wygenerowanego komunikatu żądania na poziomie drzewa DOM. Przykładowy kod:
package devbox.cxf; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.Phase; import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor; import org.w3c.dom.Node; import javax.xml.soap.*; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class FixSecurityHeaderOutInterceptor extends AbstractSoapInterceptor { public FixSecurityHeaderOutInterceptor() { super(Phase.PRE_PROTOCOL); getAfter().add(WSS4JOutInterceptor.class.getName()); } public void handleMessage(SoapMessage message) throws Fault { boolean isOutbound = message == message.getExchange().getOutMessage() || message == message.getExchange().getOutFaultMessage(); if (isOutbound) { message.getInterceptorChain().add(new FixSecurityHeaderOutEndingInterceptor()); } } public class FixSecurityHeaderOutEndingInterceptor extends AbstractSoapInterceptor { public FixSecurityHeaderOutEndingInterceptor() { super(Phase.POST_PROTOCOL_ENDING); } public void handleMessage(SoapMessage message) throws Fault { try { SOAPPart soap = (SOAPPart) message.getContent(Node.class); SOAPHeader header = soap.getEnvelope().getHeader(); // wsse:Security SOAPHeaderElement security = null; Iterator iterator = header.examineAllHeaderElements(); while (iterator.hasNext()) { SOAPHeaderElement headerElement = (SOAPHeaderElement) iterator.next(); if (headerElement.getNodeName().equals("wsse:Security")) { security = headerElement; break; } } // no security - no job if (security == null) { return; } Map<String, SOAPElement> elementMap = new HashMap<String, SOAPElement>(); Iterator childElements = security.getChildElements(); while (childElements.hasNext()) { SOAPElement element = (SOAPElement) childElements.next(); elementMap.put(element.getTagName(), element); element.detachNode(); } security.addChildElement(elementMap.get("wsu:Timestamp")); security.addChildElement(elementMap.get("wsse:BinarySecurityToken")); security.addChildElement(elementMap.get("ds:Signature")); } catch (SOAPException e) { throw new Fault(e); } } } }
Kod sprowadza się do wyłuskania elementu nagłówka, zabrania z niego wszystkich interesujących elementów i powtórne ich dodanie w kolejności akceptowalnej przez WCF. Najtrudniejsze było trafienie w odpowiednie fazy, w których ma się wykonać ten kod. Metoda prób i błędów pozwoliła trafić w dziesiątkę. Zostało jeszcze wszystko skonfigurować:
<cxf:cxfEndpoint id="cxfProducerEndpoint" xmlns:cxf="http://camel.apache.org/schema/cxf" address="${producerEndpointURI}" wsdlURL="wsdl/SomeService.wsdl"> <cxf:inInterceptors> <ref bean="producerWSS4JInInterceptor"/> </cxf:inInterceptors> <cxf:outInterceptors> <ref bean="producerWSS4JOutInterceptor"/> <bean class="devbox.cxf.FixSecurityHeaderOutInterceptor"/> </cxf:outInterceptors> </cxf:cxfEndpoint>
W przykładzie celowo pominięto szczegóły konfiguracji WSS4J, są bez znaczenia. Ważne jest, aby na końcu listy interceptorów OUT umieścić ten, który naprawia rzeczony nagłówek.
koda nima ;)
OdpowiedzUsuńjak to nima jak jest?
OdpowiedzUsuń