package at.asitplus.eidas.specific.modules.auth.eidas.v2.clients; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPFactory; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPMessage; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; import org.apache.commons.lang3.StringUtils; import org.apache.cxf.message.Message; import com.google.common.collect.Lists; import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; import lombok.extern.slf4j.Slf4j; /** * Intercepter to set unique transactionId into Apache CXF clients. * @author tlenz * */ @Slf4j public class BmiSoapTransactionHeaderInterceptor implements SOAPHandler { private static final String AUTH_NS = "http://schemas.xmlsoap.org/ws/2002/04/secext"; private static final String AUTH_PREFIX = "wss"; private static final String AUTH_ELEMENT = "Security"; private static final String TRANS_ID_NS = "http://egov.gv.at/pvp1.xsd"; private static final String TRANS_IDPREFIX = "pvp"; private static final String TRANS_ID_ELEMENT = "Client-Request-Id"; private static final String HEADER_TXID = "txid"; private static final String HEADER_PVP_TXID = "pvp-txid"; private static final String HEADER_MSG_NOT_SET = "NOT-set"; private String clientName; /** * BM.I specific header interceptor. * * @param clientType Name of the SOAP client */ public BmiSoapTransactionHeaderInterceptor(String clientType) { this.clientName = clientType; } @Override public boolean handleMessage(SOAPMessageContext context) { if (((Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY)).booleanValue()) { if (StringUtils.isNotEmpty(TransactionIdUtils.getTransactionId())) { injectTransactionId(context); } else { log.debug("No unique transactionId. Sending message without Id ..."); } } else { final Map> headers = (Map>) context.get(Message.PROTOCOL_HEADERS); log.info("response for SOAP client: {} with {}:{} and {}:{}", clientName, HEADER_TXID, extractHeaderValue(headers, HEADER_TXID), HEADER_PVP_TXID, extractHeaderValue(headers, HEADER_PVP_TXID)); } return true; } @Override public boolean handleFault(SOAPMessageContext context) { return true; } @Override public void close(MessageContext context) { } @Override public Set getHeaders() { return null; } private void injectTransactionId(SOAPMessageContext context) { try { SOAPMessage message = context.getMessage(); SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); SOAPFactory soapFactory = SOAPFactory.newInstance(); // Creating WS-Security header element SOAPElement wsSecHeaderElement = soapFactory.createElement(AUTH_ELEMENT, AUTH_PREFIX, AUTH_NS); // create transactionId element SOAPElement transactionIdElement = soapFactory.createElement(TRANS_ID_ELEMENT, TRANS_IDPREFIX, TRANS_ID_NS); transactionIdElement.setTextContent(TransactionIdUtils.getTransactionId()); wsSecHeaderElement.addChildElement(transactionIdElement); // inject header SOAPHeader header = envelope.getHeader(); if (header == null) { header = envelope.addHeader(); } header.addChildElement(wsSecHeaderElement); } catch (Exception e) { log.warn("Can NOT inject TransactionId into SOAP message. Sending message without Id ...", e); } } private String extractHeaderValue(Map> headers, String headerName) { List value = headers.getOrDefault(headerName, Lists.newArrayList(HEADER_MSG_NOT_SET)); return value.isEmpty() ? HEADER_MSG_NOT_SET : value.get(0).toString(); } }